为什么我不能在这个分配的内存块中存储一个大整数?
int *dyn = malloc(16);
*dyn = 9999999999;
printf("%llin", *dyn);
free(dyn);
在编译时,GCC警告我将发生整数溢出。果不其然,当打印出来时,它已经溢出了。
为什么我不能使用整个内存块来存储单个值?
*dyn = 9999999999;
不会指示计算机使用为dyn
分配的所有内存来存储值9999999999。
在C中,dyn
有一个类型。类型为"指向int
的指针"。然后*dyn
具有类型int
,其具有特定的、固定数量的比特。它没有表示"为dyn
分配的所有内存"的类型。
由于*dyn
是int
,*dyn = 9999999999;
告诉计算机将9999999999放入int
。由于9999999999对于C实现中的int
来说太大,因此会发生溢出。
我们可以对计算机进行编程,并设计编程语言来管理任意大小的整数。有些语言,比如Python,就是这样做的。然而,这需要额外的软件,尤其是当程序运行时,为了处理出现的任何大小的数字,必须做一些可变工作量的软件。C被设计成一种基本语言。它处理特定大小的对象,通常将C代码转换为处理器指令中的固定工作量。这些为程序员构建更大的软件提供了构建块。因此,在C中,int
对象具有固定的大小。分配16字节的内存为几个int
对象提供了空间,但它不提供大整数对象。
int的大小通常为4字节(32位(。并且,从-2147483648到2147483647,可能需要2^32个不同的状态。因此,当您尝试存储此*dyn = 9999999999;
时,会发生整数溢出。它不是指向内存位置,而是指向该变量的值。
为什么我不能使用整个内存块来存储单个值?
因为int
的大小几乎肯定不是16字节,并且当您在*dyn = 9999999999;
表达式中取消引用int
指针时,该访问被限制为int
的大小,可能是2^31-1。
请注意,整数常量9999999999
也有一个类型,该类型由编译器根据数字的大小动态确定。在这种情况下,很可能是long long
。因此,这里的实际错误是您尝试执行int x = 9999999999;
,这与malloc或指针无关。这是一个简单的溢出。
要使用大于21.4亿的数字,必须使用64位类型。使用stdint.h 中的int64_t
/uint64_t
不能在其中分配16个字节的memcpy
som值,然后通过指向某个任意整数类型的指针访问数据。这是因为有些功能失调的C型系统。简化的解释:malloc返回的数据块在内部没有类型,直到您在那里存储了一些东西。然后,它获得存储时使用的类型,所有后续访问也必须使用相同的类型,其他所有操作都会根据"严格别名规则"调用未定义的行为。
dyn
是一个整数指针(实际上,指向16字节的int数组的保留内存(。*dyn
是一个整数(此int数组中的第一个元素(。类似于阵列:
int dyn[4];
dyn[0]=9999999999;
将9999999999
分配给int
会导致变量溢出,因为int
在现代平台上只允许[-2 147 483 648,+2 147 483 647]范围(至少允许[-32767,+32767](。
9999999999
或更好地说明为9,999,999,999
不在dyn
所指向的int
的范围内,无论malloc
分配了多少内存:
int *dyn = malloc(16); // `dyn` points to an `int` object, don´t matter
// if malloc allocates 16 bytes.
*dyn = 9999999999; // Attempt to assign an out-of-range value to an `int` object.
int
类型的对象应由最现代的系统在内存中分配4个字节。
4字节最多可容纳2^(8*4(=2^32=4294967296个值。
现在您有了int
的类型,它等效于signed int
的类型。
signed int
可以存储正数和负数,但由于它可以存储负数和正数,所以它的范围大不相同。
signed int
的范围为-2147483648到2147483647,int
的范围也是如此。
因此,您不能在int
对象中保持9999999999,因为int
对象可以存储的最大值是2147483647。
如果要在对象中存储9999999999或9999999999
的值,请使用例如long long int
,但不要使用long int
,因为long int
可以保存相同范围的int
和unsigned int
:
long long int *dyn = malloc(16); // `dyn` points to an `long long int` object.
*dyn = 9999999999; // Fine, because 9999999999 is in the range of an `long long int` object.