C 2011(draft n1570)6.8 4:「次のそれぞれは完全な式です:… returnステートメントの(オプションの)式。完全な式の評価と、評価される次の完全な式の評価の間には、シーケンスポイントがあります。」</ p>
したがって、技術的には、シーケンスポイントはリターンの後ではなく、リターン内の式の評価と次の式の間にあります。が最初に0のときに呼び出されるこのコードについて考えてみます。a
int a = 0;
int Foo(void) { return a++; }
void Bar(void)
{
int b = Foo() + a;
…
}
では、またはが最初に評価されるFoo() + a
かどうFoo()
かa
は指定されていません。両方の潜在的なルール(リターン後のシーケンスポイントとリターンの式と次の完全な式の間のシーケンスポイント)に照らして、両方の順序を検討します。実装がa
最初に行う場合は、次のことを行う必要があります。
a
Sequence point
Foo()
+
次に、他の完全な式が続くので、どちらの規則でも、シーケンスポイントがあり、このコードは、私たちに関する限り、どちらの方法でも同じです。その結果b
、0に設定されます。
実装が最初に実行する場合、 「リターンFoo()
後のシーケンスポイント」ルールを使用して、実装は次のことを実行する必要があります。
Sequence point
Foo()
Sequence point
a
+
このコードには、動作が定義されているはずです。a
の副作用によって増分され、アクセスさFoo
れる前に完了してから実行されます。結果は1に設定されます。この「リターン後のシーケンスポイント」ルールでは結果は0または1になる可能性がありますが、2つの順序のどちらが使用されるかは単に指定されていません。動作は完全に未定義ではありません。a
+
a
ただし、実装が最初に実行し、「リターンの式と次の完全な式Foo()
の間のシーケンスポイント」という標準のCルールを使用する場合、次のようになります。
Sequence point
Foo()
???
a
???
+
???
「???」必要なシーケンスポイントが存在する可能性のある場所(戻り後、次の完全な式の前)にマークを付けます。この場合、の値はでアクセスおよび変更さa
れる可能性があり、間にシーケンスポイントはありません。それは未定義の動作です。a
Foo()
したがって、「リターンの式の後、次の完全な式の前のシーケンスポイント」というルールは、「リターンの直後のシーケンスポイント」とは異なります。この例では、最初の動作は未定義であり、2番目の動作は未定義です。