簡體   English   中英

GCC中的后增量,函數調用,序列點概念

[英]Post-increment, function calls, sequence point concept in 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()之前使用了評估值,並在兩次f()調用之后執行'++'操作。

我也使用llvm-clang來編譯這種情況,結果顯示b = 5,這是我所期望的。

我對后遞增和序列點行為的理解不正確嗎? 或者這是GCC461的已知問題?

除了Clang之外,您還可以使用其他兩個工具作為參考: Frama-C的價值分析KCC 我不會詳細介紹如何安裝它們或將它們用於此目的,但它們可用於檢查C程序的定義 - 與編譯器不同,它們旨在告訴您目標程序是否展示未定義行為。

他們有粗糙的邊緣,但他們都認為b絕對應該是5 ,在程序結束時沒有未定義的行為:

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

這是一個比Clang更強烈的爭論(因為如果它是未定義的行為,Clang仍然可以生成一個打印b = 5的程序)。

長話短說,看起來你在那個版本的GCC中發現了一個bug。 下一步是檢查SVN以查看它是否仍然存在。

我前段時間報告了這個海灣合作委員會的錯誤,並在今年早些時候修復了。 http://gcc.gnu.org/bugzilla/show_bug.cgi?id=48814

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM