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

时间:2016-03-02 10:40:42

标签: c++ c optimization compilation compiler-optimization

似乎C / C ++编译器(clang,gcc等)产生与优化级别相关的不同的输出。您也可以查看这篇文章中包含的在线链接。

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. 为什么no-optimization输出 14 ,而-O3的输出 10 用于相同的指令?

3 个答案:

答案 0 :(得分:4)

free(p);

This turns the contents of p into an invalid pointer value.

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

This line has no relevance for p.

if (p == q) {

This is implementation-defined behaviour because p has an invalid pointer value.

    *p = 10;

And finally, this is undefined behaviour, for the same reason as above.

C++ standard §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.

Therefore, the answers to your questions are:

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

It depends on the implementation. The C++ language does not guarantee it.

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

Because the behaviour is undefined when you dereference an invalid pointer.


In C, the comparison itself is undefined behaviour. Appendix J.2 in the C standard lists the circumstances in which the behaviour is undefined, and that list includes:

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

You may find the following question including all comments and answers interesting: Undefined, unspecified and implementation-defined behavior

答案 1 :(得分:0)

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?

This is implementation defined, you cannot rely on this behaviour. p and q can indeed be equal, you have deallocated memory pointed by p, so q might get the same address as p.

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

this is how optimizer works, you can see here your version:

https://goo.gl/yRfjIv

where compiler optimizes out assignment of 14, and here version where it looks correct:

https://goo.gl/vSVV0E

value 14 is being assigned, and I have added only one line p = q;

I am not sure why exactly it works like that, I would say that compiler assumes your code is free from undefined behaviour code and does optimizations under such assumption.

[edit]

The Undefined Behaviour is caused by the use of pointer value which compiler assumes is no longer valid, it does not matter if it is later on equal to some newly allocated memory block. The appropriate standard quote was given by 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 ]

答案 2 :(得分:-3)

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

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

在这里使用clang 3.4.1和3.6.2我一直得到正确答案,而gcc 4.2.1和5.3.0都表明了这个bug。不幸的是,clang 3.8.0也是如此。