2012-08-15 43 views
3

序列点的概念还有就是GCC产生结果的代码片段我没想到:后递增,函数调用,在GCC

(我用gcc版本4.6.1的Ubuntu/Linaro的4.6.1 -9ubuntu3为目标的i686-Linux的GNU)

[test.c的]

#include <stdio.h> 

int *ptr; 

int f(void) 
{ 
    (*ptr)++; 

    return 1; 
} 

int main() 
{ 
    int a = 1, b = 2; 

    ptr = &b; 

    a = b++ + f() + f() ? b : a; 

    printf ("b = %d\n", b); 

    return a; 
} 

在我的理解,存在在函数调用的序列点。 后增量应该在f()之前发生。

见C99 5.1.2.3: “......被称为序列点,过去评价 应完整及后续评估的无副作用应 已经发生的所有副作用。”

对于此测试用例,可能未指定评估顺序, 但最终结果应该相同。所以我预计b的最终结果是5. 但是,在编译这个案例后用'gcc test.c -std = c99',输出显示b = 3.

然后我用“gcc test.c -std = C99 -S”来看看发生了什么:

 movl $1, 28(%esp) 
     movl $2, 24(%esp) 
     leal 24(%esp), %eax 
     movl %eax, ptr 
     movl 24(%esp), %ebx 
     call f 
     leal (%ebx,%eax), %esi 
     call f 
     addl %esi, %eax 
     testl %eax, %eax 
     setne %al 
     leal 1(%ebx), %edx 
     movl %edx, 24(%esp) 
     testb %al, %al 
     je  .L3 
     movl 24(%esp), %eax 
     jmp  .L4 
.L3: 
     movl 28(%esp), %eax 
.L4: 
     movl %eax, 28(%esp) 

看来,GCC使用评估值f()之前,进行 '++' 术后2 f()的调用。

我也使用llvm-clang来编译这种情况, 和结果显示b = 5,这是我所期望的。

我的理解是不正确的后增量和序列点行为? 或者这是GCC461的已知问题?

+0

欢迎来到StackOverflow!请不要将可能想要复制的程序行粘贴 - 粘贴以供学习。 – 2012-08-21 19:34:42

+0

哦〜OK! 现在我已经删除了一些程序的行数。 感谢您的提醒! :) – 2012-08-24 06:03:23

回答

3

我前段时间报告了这个GCC bug,今年早些时候它已经修复。请参阅http://gcc.gnu.org/bugzilla/show_bug.cgi?id=48814

+0

谢谢!看来这绝对是GCC 4.6.1中的一个bug。我将检出最新的GCC版本,并将其构建,然后再次尝试此示例。非常感谢! :) – 2012-08-24 06:09:29

4

除了Clang,还有其他两个工具可以用作参考:Frama-C's value analysisKCC。我不会详细介绍如何安装它们或将它们用于此目的,但它们可用于检查C程序的定义 - 与编译器不同,它们旨在告诉您目标程序是否展示未定义行为。

他们有他们的棱角,但他们都认为b绝对应该5用在程序的末尾没有未定义行为:

Mini:~/c-semantics $ dist/kcc ~/t.c 
Mini:~/c-semantics $ ./a.out 
b = 5 

这是一个更有力地证明比锵这样想(因为如果它是未定义的行为,Clang仍然可以生成打印b = 5的程序)。

长话短说,它看起来像你已经发现在该版本的海湾合作委员会的错误。下一步是检查SVN,看看它是否仍然存在。

+0

谢谢!这些是验证程序的非常有用的工具!顺便说一句,Johannes Schaub说他报告了这个错误,并且今年是固定的。我会检查最新的GCC版本并再次尝试。 :) – 2012-08-24 06:17:14