编译器可以假设 malloc 永远不会返回 NULL 吗?

Can the compiler assume that malloc will never return NULL?

提问人:Agiltohr 提问时间:2/15/2023 最后编辑:Eric PostpischilAgiltohr 更新时间:2/15/2023 访问量:146

问:

在本视频中提到,编译器可以假设它永远不会返回,并允许相应地进行优化。我从未听说过这个,在 C 标准中也找不到任何参考。谁能告诉我这是否属实,如果是,这种行为是在哪里指定的?mallocNULL

此时视频中显示的代码为:

if((a = malloc(1024)) == NULL)
    printf("We are out of memory!\n");
else
    free(a);
c 内存 null malloc

评论

2赞 wohlstad 2/15/2023
这不是真的,至少不是一般意义上的。也许在某些特定的环境中,malloc 可以保证成功,但我不熟悉它们。
2赞 teapot418 2/15/2023
open-std.org/jtc1/sc22/wg14/www/docs/n1548.pdf(C11 标准)< - “malloc 函数返回空指针或指向已分配空间的指针。”
0赞 Some programmer dude 2/15/2023
让我们举一个更简单的例子:.很容易看出,这可以转换为 .这基本上就是视频的那部分内容:如果对程序无关紧要,编译器可以简单地删除(或不包含)部分代码。这是允许的,因为好像规则。至少我希望视频的作者是这样的。因为没有“假设”内存总是可以分配的。int a = 10; if (a == 10) { a = 5; }int a = 5;
0赞 Some programmer dude 2/15/2023
这并不是说它可能会返回非 null 指针,因为在某些操作系统上,它几乎永远不会返回。以 Linux 为例,它使用内存分配的过量使用,即使虚拟内存过量使用,分配也几乎永远不会失败。这是因为很少有应用程序使用其分配的内存中的所有页面,或者确实以页面可以重用于其他进程的方式使用它们,因此操作系统可以在进程之间切换页面以满足大多数用例。malloc
0赞 tstanisl 2/15/2023
@Mat,我不明白为什么。如果指向已分配对象的指针的值在外部不可观察,则可以通过假设它始终成功来优化它。malloc()

答:

4赞 Eric Postpischil 2/15/2023 #1

说话者并不意味着编译器可以假定从不返回 null 指针。它们意味着在所示的特定情况下,编译器可以看到代码的作用,并且可以在不调用的情况下实现它,并且等效地,它可以被优化,就好像在特定情况下从不返回 null 一样。mallocmallocmalloc

C 标准允许编译器以产生指定可观察行为的任何方式实现代码,即从 C 2018 5.1.2.3 6 开始:

  • 对易失性对象的访问严格按照抽象机器的规则进行评估。
  • 在程序终止时,写入文件的所有数据应与根据抽象语义执行程序所产生的结果相同。
  • 交互式设备的输入和输出动态应按照 7.21.3 的规定进行。这些要求的目的是尽快出现无缓冲或行缓冲的输出,以确保提示消息在程序等待输入之前实际出现。

请注意,这不是可观察行为的一部分。它位于 C 实现内部,这意味着允许编译器优化其行为方式。即使有一个单独的库提供 ,编译器也可以将其视为对 C 实现的辅助,并优化程序中的使用。mallocmallocmalloc

评论

1赞 wohlstad 2/15/2023
说话者实际上明确表示(大约 1:04:19)编译器可以假设内存是可分配的,因此 malloc 不会返回 NULL。这在我看来是错误的。
2赞 DevSolar 2/15/2023
调用的返回可能远远超出了编译器或库实现的控制范围,除非该库实现本身已优化了系统调用,并已告知编译器它已这样做。目前,在标准范围内如何实现的机制使我无法理解。无论如何,在一般情况下,它不可能是一个有效的优化,因为一般情况下,很可能会返回。malloc()NULLmalloc()malloc()NULL
2赞 Eric Postpischil 2/15/2023
@SupportUkraine:编译器根本不需要调用外部例程。C 标准对 C 实现的要求是它向程序提供 C 2018 7.22.3 中指定的内存管理功能。如果编译器显示“嘿,我可以给你你想要的内存,而无需调用外部”,这是一个有效的优化。想象一下,程序在抽象机器内执行,这就是 C 标准指定它的方式。在该抽象计算机中,程序调用 ,获取指向 1024 字节的指针,...mallocmallocmalloc
2赞 Eric Postpischil 2/15/2023
...看到指针不为空(因为这个抽象机器在源代码中的此时总是有可用的内存),并调用 .因此,C 标准完全允许程序以这种方式运行。现在,你将如何实现抽象机器的这种行为?您不必调用物理机中的外部设备即可执行此操作。我们知道程序的行为是什么:这个特定的代码没有可观察到的副作用。因此,我们可以通过什么都不做来实现它,包括不调用外部。freemallocmalloc
3赞 Eric Postpischil 2/15/2023
@SupportUkraine:Clang 进行此优化。