GCC が予期しない結果を生成するコード フラグメントがあります。
(ターゲット i686-linux-gnu には gcc バージョン 4.6.1 Ubuntu/Linaro 4.6.1-9ubuntu3 を使用しています)
[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 の既知の問題ですか??