LLVM和GCC,不同的输出相同的代码

zag*_*ago 2 c compiler-construction macos gcc llvm

这是一个示例代码,用于显示LLVM编译器和GCC的不同输出.我想知道为什么?答案应该很简单,但我看不到它.(Xcode 4.6.1)

代码:

#include <stdio.h>

#define MAX(a,b) ( (a) > (b) ? (a) : (b) )

int increment() {
    static int i = 42;
    i += 5;
    printf("increment returns %d\n",i);
    return i;
}

int main( int argc, char ** argv ) {
    int x = 50;
    printf("max of %d and %d is %d\n", x,increment(),MAX(x, increment()));
    printf("max of %d and %d is %d\n", x,increment(),MAX(x, increment()));
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

LLVM输出:

increment returns 47
increment returns 52
increment returns 57
max of 50 and 47 is 57
increment returns 62
increment returns 67
increment returns 72
max of 50 and 62 is 72
Run Code Online (Sandbox Code Playgroud)

GCC输出:

increment returns 47
increment returns 52
max of 50 and 52 is 50
increment returns 57
increment returns 62
increment returns 67
max of 50 and 67 is 62
Run Code Online (Sandbox Code Playgroud)

Kir*_*rov 13

未定义参数的评估顺序.所以这:

printf("max of %d and %d is %d\n", x,increment(),MAX(x, increment()));
Run Code Online (Sandbox Code Playgroud)

导致未定义的未指定行为.这就是为什么你在两个编译器上都有不同的结果.

另一个(潜在的)问题是:MAX- 它可能导致两次调用increment.避免使用这样的宏.

  • 不,那不是未定义的行为.这是*未指明的行为*.调用增量时,增量返回时以及三元运算符中有序列点. (6认同)
  • @KirilKirov很好的回答.该标准没有规定未定义行为的要求.正如两个词的统一所暗示的那样,"未定义的行为"确实意味着*任何事情都可能发生*.未指定的行为意味着使用两种或更多种可能行为中的一种.在这种情况下,似乎有八个(或更多)订单可以评估表达式.实现定义的行为是指定实现需要记录的未指定行为. (3认同)