C - 错误分配 1TB 内存不会失败?


//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 okn");
return 0;
}

编译器选项:-Wall -std=c99 -o a.out source_file.c

输出("一切都很好")让我感到困惑。我显然没有 1TB 的内存 - 根据 C 参考,malloc 应该返回 NULL,如果且仅当(!)出现问题。

这显然不会在这里发生。有人能解释一下吗?

1024 * 1024

* 1024 * 1024

这些是int类型的整数常量。当相乘时,操作将在类型int上执行。结果的类型为int

int很可能无法在系统上保存大于 2^32/2 -1 =2.14*10^9的值。

这意味着您溢出有符号的 int 并调用未定义的行为。任何事情都可能发生,包括malloc分配一些随机的数据块。

根据 C-Reference,malloc 应该返回 NULL,当且仅当(!)出现问题时。

这是不正确的。

malloc()在 2 种情况下返回NULL

  1. 如果无法分配内存,则为空指针

  2. 在分配 0 时,如果malloc()返回NULL或非NULL指针(不能取消引用),则定义实现。

OP 的1024 * 1024 * 1024 * 1024溢出 32int位数学,这是未定义的行为或 UB。 @WhozCraig提示。典型的结果是截断的乘积为 0。然后,OP 的系统返回一个非NULL指针用于零字节分配,因为未打印"无法保留内存!"。

如果OP的平台使用罕见的64位int,内存的真正分配可能会延迟。


OP也错过了编译器的有用建议。 增加警告选项。 某些以下人员将报告警告。

// -pedantic -Wall -Wextra -std=c99  -o a.out source_file.c
int *arr = malloc(1024 * 1024 * 1024 * 1024);
// warning: integer overflow in expression [-Woverflow]

确保表达式的数学类型满足/超过目标的类型。 不使用

100*1000*1000@Olaf原因
int *arr = malloc((size_t) 1024 * 1024 * 1024 * 1024);

malloc(3)手册页:

默认情况下,Linux 遵循乐观的内存分配策略。这意味着当 malloc() 返回非 NULL 时,不能保证内存确实可用。

当然,这是假设你在Linux上。

您没有 1TB 的物理内存,但大多数操作系统都支持虚拟内存,由磁盘空间提供支持。 当 malloc 请求内存时,系统会分配虚拟内存。其中一部分将是真实内存,其余部分很可能是高清上的文件。

1024 * 1024 * 1024 * 1024最有可能调用未定义的行为:1024是一个int常数。操作是使用两个操作数的"最大"类型完成的,但至少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)是定义NULL或指针的实现,不得用于访问对象。

请记住,您的代码可能会返回一个非 null 指针,该指针不得用于访问。但是当你只是测试它时,它很好,但没用。

相关内容

  • 没有找到相关文章

最新更新