1

コンマ シーケンス演算子は、式にシーケンス ポイントを導入します。これは、以下のプログラムが未定義の動作を回避することを意味するかどうか疑問に思っています。

int x, y;

int main()
{
  return (x++, y) + (y++, x);
}

未定義の動作を回避する場合でも、未指定のままである可​​能性があります。つまり、いくつかの可能な値の 1 つを返します。C99 では しか計算できないと思いますが1、実際には、さまざまなバージョンの GCC がこのプログラムを を返す実行可能ファイルにコンパイルします2。Clang は を返す実行可能ファイルを生成します。これ1は私の直感と一致しているようです。

最後に、これはC11で変更されたものですか?

4

4 に答える 4

6

次の式を使用します。

(x++, y) + (y++, x)

左から右に評価します。

x++  // yield 0, schedule increment of x
,    // sequence point: x definitely incremented now
y    // yield 0
y++  // yield 0, schedule increment of y
// explode because you just read from y and wrote to y
// with no intervening sequence point

これを禁止する標準は何もないため、全体の動作は未定義です。

次の疑似コードを比較してください。

f() { return x++, y; }
g() { return y++, x; }
f() + g()

C99 (5.1.2.3/2) によると、fおよびの呼び出しg自体が副作用としてカウントされ、関数呼び出し演算子には、関数に入る直前にシーケンス ポイントが含まれます。これは、関数の実行がインターリーブできないことを意味します。

「並行して評価する」モデルでは、次のようになります。

f()  // arbitrarily start with f: sequence point; enter f
g()  // at the same time, start calling g: sequence point

の実行f自体が副作用としてカウントされるため、 のシーケンス ポイントは、が戻るg()まで実行を中断します。fしたがって、未定義の動作はありません。

于 2012-12-18T15:59:00.003 に答える
5

規格の 6.5 章全体で、演算子ごとの評価の順序について言及されています。私が見つけた評価の順序の最良の要約は、標準の (非規範的な) 付属書 J でした。

C11 附属書 J

J.1 規定されていない振る舞い

  • 関数呼び出し ()、&&、||、?:、およびコンマ演算子 (6.5) で指定されている場合を除き、部分式が評価される順序と副作用が発生する順序

あなたの例では、 + 演算子のオペランドの評価順序が指定されていないため、部分式(x++, y)orが最初に評価されるかどうかはわかりません。(y++, x)

未定義の動作に関しては、コンマ演算子は何も解決しませんでした。(x++, y)が最初に評価される場合、他のサブ式のy直前に評価される場合があります。y++格納する値を決定する以外の目的で、シーケンス ポイントを介さずに y が 2 回アクセスされるため、動作は未定義です。詳細はこちら。

したがって、プログラムには未定義と未指定の両方の動作があります。

(さらに、int main() ではなく int main() が、ホストされたアプリケーションの main の明確に定義されたバージョンの 1 つではないため、実装定義の動作があります。)

于 2012-12-18T16:13:05.250 に答える
1

標準では、どの演算子がシーケンス ポイントを導入するかを明示的に宣言しています+が、その中には含まれていません。したがって、式は、禁止された部分式が互いに "近く" 評価されるように評価することができ、その間にシーケンス ポイントはありません。

実際には、この禁止には理由があります。つまり、そのような操作のオペランドの評価が並行してスケジュールされる可能性があるためです。このような評価モデルの下では、何かが起こる可能性があり、結果が予測できないことを簡単に納得させることができます。

あなたのおもちゃの例では、競合は予測可能ですが、部分式でポインターの間接化を使用する場合、必ずしもそうではありません。そうすると、部分式の 1 つが潜在的に別の部分式に別名を付ける可能性があるかどうかがわかりません。したがって、このタイプの最適化を許可したい場合、基本的にCができることはあまりありません。

于 2012-12-18T16:54:45.573 に答える
1

私の理解では、次の評価命令のいずれも合法です。

  • x++, y++, y, x
  • x++, y, y++, x
  • x++, y++, x, y
  • y++, x, x++, y
  • ...

だがしかし:

  • y, x++, x, y++
  • ...

私の理解では、必要な唯一の順序は、 that (x++)must come before(y)(y++)must come before(x)です。

したがって、これはまだ未定義の動作だと思います。

于 2012-12-18T15:26:46.740 に答える