简体   繁体   English

GCC中的后增量,函数调用,序列点概念

[英]Post-increment, function calls, sequence point concept in GCC

There is a code fragment that GCC produce the result I didn't expect: 有一个代码片段,GCC产生我没想到的结果:

(I am using gcc version 4.6.1 Ubuntu/Linaro 4.6.1-9ubuntu3 for target i686-linux-gnu) (我正在使用gcc版本4.6.1 Ubuntu / Linaro 4.6.1-9ubuntu3用于目标i686-linux-gnu)

[test.c] [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;
}

In my understanding, there is a sequence point at function call. 根据我的理解,函数调用有一个序列点。 The post-increment should be taken place before f(). 后增量应该在f()之前进行。

see C99 5.1.2.3: "... called sequence points, all side effects of previous evaluations shall be complete and no side effects of subsequent evaluations shall have taken place." 见C99 5.1.2.3:“......称为序列点,先前评估的所有副作用应完整,后续评估不会产生副作用。”

For this test case, perhaps the order of evaluation is unspecified, but the final result should be the same. 对于此测试用例,可能未指定评估顺序,但最终结果应相同。 So I expect b's final result is 5. However, after compiling this case with 'gcc test.c -std=c99', the output shows b = 3. 所以我希望b的最终结果是5.但是,在用'gcc test.c -std = c99'编译这个例子后,输出显示b = 3。

Then I use "gcc test.c -std=c99 -S" to see what happened: 然后我用“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)

It seems that GCC uses evaluated value before f() and perform '++' operation after two f() calls. 似乎GCC在f()之前使用了评估值,并在两次f()调用之后执行'++'操作。

I also use llvm-clang to compile this case, and the result shows b = 5, which is what I expect. 我也使用llvm-clang来编译这种情况,结果显示b = 5,这是我所期望的。

Is my understanding incorrect on post-increment and sequence point behavior ?? 我对后递增和序列点行为的理解不正确吗? Or this is a known issue of GCC461 ?? 或者这是GCC461的已知问题?

In addition to Clang, there are two other tools that you can use as reference: Frama-C's value analysis and KCC . 除了Clang之外,您还可以使用其他两个工具作为参考: Frama-C的价值分析KCC I won't go into the details of how to install them or use them for this purpose, but they can be used to check the definedness of a C program—unlike a compiler, they are designed to tell you if the target program exhibits undefined behavior. 我不会详细介绍如何安装它们或将它们用于此目的,但它们可用于检查C程序的定义 - 与编译器不同,它们旨在告诉您目标程序是否展示未定义行为。

They have their rough edges, but they both think that b should definitely be 5 with no undefined behavior at the end of your program: 他们有粗糙的边缘,但他们都认为b绝对应该是5 ,在程序结束时没有未定义的行为:

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

This is an even stronger argument than Clang thinking so (since if it was undefined behavior, Clang could still generate a program that prints b = 5 ). 这是一个比Clang更强烈的争论(因为如果它是未定义的行为,Clang仍然可以生成一个打印b = 5的程序)。

Long story short, it looks like you have found a bug in that version of GCC. 长话短说,看起来你在那个版本的GCC中发现了一个bug。 The next step is to check out the SVN to see if it's still present there. 下一步是检查SVN以查看它是否仍然存在。

I reported this GCC bug some time ago and it was fixed earlier this year. 我前段时间报告了这个海湾合作委员会的错误,并在今年早些时候修复了。 See http://gcc.gnu.org/bugzilla/show_bug.cgi?id=48814 http://gcc.gnu.org/bugzilla/show_bug.cgi?id=48814

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM