【问题标题】:LLVM and GCC, different output same codeLLVM和GCC,不同的输出相同的代码
【发布时间】:2013-04-10 15:13:01
【问题描述】:

这是一个示例代码,只是为了显示 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;
}

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

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

【问题讨论】:

  • 您说的是您的 XCode 版本,但您使用的是哪个版本的 GCC?也许你可以在终端输入gcc -v

标签: c macos gcc compiler-construction llvm


【解决方案1】:

参数的评估顺序未定义指定。所以这个:

printf("max of %d and %d is %d\n", x,increment(),MAX(x, increment()));

导致undefined未指定的行为。这就是为什么您在两个编译器上得到不同结果的原因。

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

【讨论】:

  • 查看stackoverflow.com/questions/376278/…了解更多信息,尤其是那里的优秀链接。
  • @DavidGrayson,因为47小于50,所以不执行三元表达式的假分支。
  • 没有。这不是未定义的行为。这是未指定的行为。在调用增量时、增量返回时以及在三元运算符中都有序列点。
  • @KirilKirov 好答案。该标准没有对未定义行为提出任何要求。正如这两个词的统一所暗示的那样,“未定义的行为”实际上意味着任何事情都可能发生。未指定的行为意味着使用了两种或多种可能的行为之一。在这种情况下,似乎有八个(或更多)顺序可以评估表达式。实现定义的行为是实现需要记录的未指定行为。
【解决方案2】:

LLVM 代码根据 ANSI C 生成正确的结果。如果您不希望在每个打印语句中多次调用 increment,请将返回值保存在变量中并使用它。精神上单步执行代码,显示应该是 增量返回 47 增量返回 52 增量返回 57 50 和 47 的最大值为 57 增量返回 62 增量返回 67 50 和 62 的最大值为 72 所以我最初的反应和对代码的研究是错误的,而 LLVM 输出是正确的。 LLVM 结果的原因是 main 中的每个打印语句都调用了 3 次增量。使此代码打印合理输出的方法是将增量返回的值保存在变量中并打印该变量,而不是再次调用增量。据我所知,结果的差异并不取决于未定义的行为,而是取决于对 ANSI C 的正确与错误一致性。

【讨论】:

猜你喜欢
  • 2017-05-21
  • 1970-01-01
  • 2018-01-29
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多