10

このコードを実行すると、出力は 11, 10 になります。

一体なぜそれができるのでしょうか?うまくいけば私を啓発するこれについて誰かが私に説明を与えることができますか?

ありがとう

#include <iostream>
using namespace std;

void print(int x, int y)
{ 
    cout << x << endl;
    cout << y << endl;
}
int main()
{
    int x = 10;
    print(x, x++);
}
4

5 に答える 5

20

C++ 標準の状態 (セクション 1.9.16 の注記):

異なる引数式に関連付けられた値の計算と副作用は順序付けされていません。

つまり、値が関数に渡される前に引数が評価される順序は、未定義および/またはコンパイラに依存します。そのため、一部のコンパイラ (最初に左の引数を評価する) ではそのコードが出力され、10, 10他のコンパイラ (最初に右の引数を評価する) では出力されます11, 10。一般に、未定義の動作に依存するべきではありません。

これを理解するのを助けるために、関数が呼び出される前に各引数式が評価されると想像してください (これが実際にどのように機能するかということではなく、シーケンスを理解するのに役立つ簡単な考え方です):

int arg1 = x;       // This line
int arg2 = x++;     // And this line can be swapped.
print(arg1, arg2);

C++ 標準では、2 つの引数式は順序付けされていないと述べています。したがって、このように別の行に引数式を書き出す場合、それらの順序は重要ではありません。標準では、引数式は任意の順序で評価できると述べているためです。上記の順序で評価するコンパイラもあれば、入れ替えるコンパイラもあります。

int arg2 = x++;     // And this line can be swapped.
int arg1 = x;       // This line
print(arg1, arg2);

これにより、値を保持しながらarg2、値を保持する方法が明らかになります。10arg111

コード内でこの未定義の動作を常に回避する必要があります。

于 2012-06-16T05:06:51.060 に答える
8

全体として、ステートメント:

 print(x, x++);

未定義動作になります。プログラムが未定義の動作をすると、それは有効なC ++プログラムではなくなり、文字通りどのような動作も可能になります。したがって、そのようなプログラムの理由を見つけることは無意味です。


なぜこの未定義動作なのですか?

プログラムを段階的に評価して、それが未定義動作を引き起こすことを疑いの余地なく証明できるところまで見ていきましょう。

関数への引数の評価の順序は指定されていません[参照1]

不特定とは、実装がこの特定の機能を必要に応じて実装できることを意味し、その詳細を文書化する必要はありません。

上記のルールを関数呼び出しに適用します。

print(x, x++);

実装はこれを次のように評価する可能性があります。

  • 左から右または
  • 右から左または
  • 任意の魔法の順序(3つ以上の関数の引数の場合

つまり、C ++標準に従って実装する必要がないため、特定の順序に従う実装に依存することはできません。

C / C ++では、シーケンスポイントが介在しない限り、変数の読み取りまたは書き込みを2回以上行うことはできません[参照2]。そうすると、未定義動作が発生します。いずれかの引数が前述の関数で最初に評価されるかどうかは関係ありません。 、それらの間にシーケンスポイントはありません。シーケンスポイントは、すべての関数引数の評価後にのみ存在します[参照3]

この場合x、介在するシーケンスポイントなしでアクセスされているため、未定義の動作が発生します。

簡単に言えば、そのような未定義動作を呼び出さないコードを書くのが最善です。そうすると、そのようなプログラムから特定の動作を期待することができないからです。


[参照1] C++ 03標準§5.2.2.8
パラ8:

[...]関数の引数の評価の順序は指定されていません。[...]


[参照2] C++ 03 5式[expr]:
パラ4:

....
前のシーケンスポイントと次のシーケンスポイントの間で、スカラーオブジェクトは、式の評価によって、格納されている値を最大で1回変更する必要があります。さらに、前の値は、保存される値を決定するためにのみアクセスされるものとします。この段落の要件は、完全な式の部分式の許容される順序ごとに満たされるものとします。それ以外の場合、動作は未定義です。


[参照3] C++ 03 1.9プログラムの実行[intro.execution]:
パラ17:

関数を呼び出す場合(関数がインラインであるかどうかに関係なく)、すべての関数の引数(存在する場合)の評価後、関数本体の式またはステートメントの実行前に実行されるシーケンスポイントがあります。

于 2012-06-16T05:33:02.883 に答える
4

x++ は関数パラメーターであり、指定されていない順序で評価される可能性があります。これは、動作が未定義であり、移植可能 (または合法的) ではないことを意味します。

于 2012-06-16T05:04:54.540 に答える
0

これは、最後の引数が最初に入る関数呼び出しスタックに関係していると思います。したがって、x++ はあなたの y であり、x は print() のローカル x です。

于 2012-06-16T05:23:31.860 に答える