【问题标题】:Post-increment, function calls, sequence point concept in GCCGCC 中的后增量、函数调用、序列点概念
【发布时间】:2012-08-11 14:33:48
【问题描述】:

有一段代码是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() 之前使用评估值并执行 '++' 两次 f() 调用后的操作。

我也使用llvm-clang来编译这个案例, 结果显示 b = 5,这是我所期望的。

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

【问题讨论】:

  • 欢迎来到 StackOverflow!请不要对可能想复制粘贴学习的程序行编号。
  • 哦~好的!现在我已经删除了程序的行数。谢谢提醒! :)

标签: c c99 gcc4 sequence-points


【解决方案1】:

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

他们有其粗糙的边缘,但他们都认为b 绝对应该是@​​987654324@,在程序结束时没有未定义的行为:

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

这是一个比 Clang 认为的更强大的论点(因为如果它是未定义的行为,Clang 仍然可以生成一个打印 b = 5 的程序)。

长话短说,您似乎在该版本的 GCC 中发现了一个错误。下一步是检查 SVN,看看它是否仍然存在。

【讨论】:

  • 谢谢!这些是验证程序的非常有用的工具!顺便说一句,Johannes Schaub 说他报告了这个错误,并在今年早些时候得到了修复。我将检查最新的 GCC 版本并再试一次。 :)
【解决方案2】:

我前段时间报告了这个 GCC 错误,今年早些时候已修复。见http://gcc.gnu.org/bugzilla/show_bug.cgi?id=48814

【讨论】:

  • 谢谢!似乎这绝对是 GCC 4.6.1 中的一个错误。我将检查最新的 GCC 版本,构建它,然后再次尝试这个示例。太感谢了! :)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-06-25
  • 1970-01-01
  • 2014-07-18
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多