//gcc 5.4.0
#include <stdio.h>
int main(void)
{
// Try to reserve 1 TB of memory
int *arr = malloc(1024 * 1024 * 1024 * 1024);
// Unfortunately most systems will actually allow this (swapping etc.)
if (arr == NULL) {
printf("Was not able to reserve memory!\n");
}
printf("Everything is ok\n");
return 0;
}
编译器选项:-Wall -std=c99 -o a.out source_file.c
输出(&#34;一切都好,#34;)让我感到困惑。我显然没有1TB的内存 - 根据C-Reference,malloc应该返回NULL,并且只有当(!)出现问题时才会返回。
这显然不会发生在这里。有人可以解释一下吗?
答案 0 :(得分:2)
1024 * 1024 * 1024 * 1024
这些是int
类型的整数常量。当相乘时,操作将在int
类型上执行。结果将是int
类型。
int
很可能无法在系统上保存大于2 ^ 32/2 -1 = 2.14*10^9
的值。
意味着溢出signed int并调用未定义的行为。任何事情都可能发生,包括malloc分配一些随机数据块。
答案 1 :(得分:2)
根据C-Reference,malloc应该返回NULL,并且只有当(!)出现问题时才会返回。
这是不正确的。
malloc()
在两个条件下返回NULL
:
如果无法分配内存,则空指针。
在分配0时,如果malloc()
返回NULL
或非NULL
指针(无法取消引用),则执行定义。
OP的1024 * 1024 * 1024 * 1024
溢出32位int
数学,这是未定义的行为或UB。 @WhozCraig hint。典型的结果是截断的乘积为0. OP的系统然后返回非NULL
指针,用于零字节分配,因为&#34;不能保留记忆!\ n&#34;没打印。
如果OP的平台使用罕见的64位int
,则内存的真实分配可能是deferred。
// -pedantic -Wall -Wextra -std=c99 -o a.out source_file.c
int *arr = malloc(1024 * 1024 * 1024 * 1024);
// warning: integer overflow in expression [-Woverflow]
确保表达式的数学类型符合/超过目标类型。 @Olaf和reasons not to use 100 * 1000 * 1000
int *arr = malloc((size_t) 1024 * 1024 * 1024 * 1024);
答案 2 :(得分:0)
来自malloc(3)
联机帮助页:
默认情况下,Linux遵循乐观的内存分配策略。这意味着当malloc()返回非NULL时,无法保证内存确实可用。
当然,这假设你在Linux上。
答案 3 :(得分:-1)
您没有1TB物理内存,但大多数操作系统都支持虚拟内存,并以磁盘空间为后盾。 当malloc请求内存时,系统会分配虚拟内存。它的一部分将是真正的内存,其余部分很可能是你的高清文件。
答案 4 :(得分:-2)
1024 * 1024 * 1024 * 1024
最有可能调用未定义的行为:
1024
是int
常量。使用&#34;最大的&#34;完成操作。两个操作数的类型,但至少int
。两个操作数均为int
,因此乘法类型为int * int -> int
。以下乘法相同。即最终结果是int
。在典型系统上int
不超过32位。 参数的类型与表达式无关。。
乘法的结果溢出int
(除非它超过41位),这会调用未定义的行为。任何事情都可能发生(通常但不保证:结果被截断,产生0
)。
为避免这种情况,您应该使用(size_t)1024 * 1024 * 1024 *1024
。这将(根据转换规则)将使用您系统上的size_t
标准类型执行计算。
事先使用静态断言来确保size_t
可以表示结果:
_Static_assert(SIZE_MAX >= 1024ULL * 1024 * 1024 *1024, "size_t is too small");`
如果没有这个,乘法会在一个太小的size_t
上被截断(对于有符号和无符号整数,规则是不同的!)并且最终传递0
。
根据标准malloc(0)
is implementation defined either NULL
or a pointer which must not be used to access an object。
记住所有这些,您的代码可能会返回一个非空指针,该指针不能用于访问。但是当你测试它时,它很好,但没用。