为什么不能在动态分配的内存块中存储一个非常大的单个值?

Why can't you store an extremely large single value in a dynamically allocated block of memory?

为什么我不能在这个分配的内存块中存储大整数?

int *dyn = malloc(16);
*dyn = 9999999999;

printf("%lli\n", *dyn);

free(dyn);

在编译时,GCC 警告我将发生整数溢出。果然,打印出来的时候,已经溢出了

为什么我不能使用整个内存块来存储单个值?

dyn是一个整型指针(实际上是指向一个16字节的int数组的预留内存)。 *dyn 是一个整数(此 int 数组的第一个元素)。类似于数组:

int dyn[4];
dyn[0]=9999999999;

9999999999 赋值给 int 会导致变量溢出,因为 int 在现代平台上只允许 [−2 147 483 648, +2 147 483 647] 范围(和至少 [−32767, +32767]).

int的大小通常为4字节(32位)。而且,它可以采用 2^32 个不同的状态,从 -2147483648 到 2147483647。 因此,当您尝试存储此 *dyn = 9999999999; 时,会发生整数溢出。 它不是指向内存位置,而是指向该变量的值。

*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 对象提供 space,但不提供大整数对象。

Why can't I use the entire block of memory to store a single value?

因为 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 返回的数据块在内部没有类型,直到你在那里存储一些东西。然后它获取您在存储时使用的类型,并且所有后续访问也必须使用相同的类型,其他所有内容都会根据 "the strict aliasing rule".

调用未定义的行为

9999999999 或更好地说明 9,999,999,999 不在 int 的范围内,dyn 指向该范围,无论内存有多大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 = 4,294,967,296 个值。

现在你有了 int 的类型,它等同于 signed int 的类型。

signed int 可以存储正数和负数,但是由于它可以存储正数和负数,所以它的范围很不一样。

signed int 的范围是 -2,147,483,648 到 2,147,483,647,int.

的范围也是如此

所以你不能int对象中保存9,999,999,999,因为int对象可以存储的最大值是2,147,483,647。

如果要在对象中存储 9,999,999,999 或 9999999999 的值,请使用 f.e。 long long int,但不是 long int,因为 long int 可以包含 intunsigned 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.