C/C++ 不确定值:编译器优化给出不同的输出(示例)

C/C++ Indeterminate Values: Compiler optimization gives different output (example)

C/C++ 编译器(clang、gcc 等)似乎会产生与优化级别相关的不同 输出。您不妨查看此post中包含的在线link。

http://cpp.sh/5vrmv(将输出从 none 更改为 -O3 以查看差异)。

基于下面的一段代码,有人可以解释我的几个问题吗:

#include <stdio.h>
#include <stdlib.h>

int main(void) {

    int *p = (int *)malloc(sizeof(int));
    free(p);
    int *q = (int *)malloc(sizeof(int));
    if (p == q) {
        *p = 10;
        *q = 14;
        printf("%d", *p);
    }
    return 0;
}
  1. 执行一定会进入if语句吗?我们如何知道两个指针 p 和 q 的地址相同?
  2. 为什么没有优化输出 14,而 -O3 对于相同的指令输出 10

Is it certain that the execution will always get into the if statement? How do we know the addresses of the two pointers, p and q, will be the same?

这是实现定义的,您不能依赖此行为。 pq 确实可以相等,你已经释放了 p 指向的内存,所以 q 可能会得到与 p 相同的地址。

Why does no-optimization has output 14, while -O3 has output 10 for the same instructions?

这是优化器的工作方式,您可以在此处查看您的版本:

https://goo.gl/yRfjIv

其中编译器优化了 14 的赋值,这里是看起来正确的版本:

https://goo.gl/vSVV0E

正在分配值 14,我只添加了一行 p = q;

我不确定为什么它会那样工作,我会说编译器假定您的代码没有未定义的行为代码,并在这种假设下进行优化。

[编辑]

未定义行为是由于使用了编译器认为不再有效的指针值引起的,如果它稍后等于某个新分配的内存块并不重要。 TartanLlama 给出了适当的标准报价:

[basic.stc.dynamic.safety]

[ Note: the effect of using an invalid pointer value (including passing it to a deallocation function) is undefined, see 3.7.4.2. This is true even if the unsafely-derived pointer value might compare equal to some safely-derived pointer value. —end note ]

free(p);

这会将 p 的内容变成无效的指针值。

int *q = (int *)malloc(sizeof(int));

此行与 p 无关。

if (p == q) {

这是实现定义的行为,因为p有一个无效的指针值。

    *p = 10;

最后,这是 未定义 行为,原因与上述相同。

C++ 标准 §3.7.4.2/4:

If the argument given to a deallocation function in the standard library is a pointer that is not the null pointer value (4.10), the deallocation function shall deallocate the storage referenced by the pointer, rendering invalid all pointers referring to any part of the deallocated storage. Indirection through an invalid pointer value and passing an invalid pointer value to a deallocation function have undefined behavior. Any other use of an invalid pointer value has implementation-defined behavior.

因此,您的问题的答案是:

Is it certain that the execution will always get into the if statement?

这取决于实施。 C++语言不保证。

Why does no-optimization has output 14, while -O3 has output 10 for the same instructions?

因为取消引用无效指针时行为未定义。


在 C 中,比较本身是未定义的行为。 C 标准中的附录 J.2 列出了未定义行为的情况,该列表包括:

The value of a pointer to an object whose lifetime has ended is used.

您可能会发现以下问题(包括所有评论和答案)很有趣:Undefined, unspecified and implementation-defined behavior

if-条件可能为假——取决于 malloc() 的特定实现,它可能 return 刚刚释放的块以供重用或不同的块。

但是,如果程序打印 anything(因为碰巧 q 等于 p),它必须打印 14。产生其他任何东西的编译器都是有问题的...

在这里使用 clang 3.4.1 和 3.6.2 我总是得到正确的答案,而 gcc 4.2.1 和 5.3.0 都显示了这个错误。不幸的是,clang 3.8.0 也是如此。