0

次のように簡単な関数を書きました...

int fun(int *i, int *j) 
{  
     *i += 3; 
     *j += *i; 
     return (*i + *i); 
}

そして、メイン関数では、次のように関数を呼び出しました...

int main()
{
    int x = 3, y = 2, a, b; 
    a = x + y + fun(&x, &y) + x; 
    b = y + fun(&x, &y) + y;

    cout<<" a = " << a << "\n";
    cout<<" b = " << b << "\n";

}

質問は、出力が期待どおりではなかったことです

実行後、これは出力でした

a=23
b=52

私は期待していました

a=23 
b=46

誰かが説明できるかどうかは正確にはわかりません。

4

3 に答える 3

5

との評価の順序が不定であるため、式を評価した結果はunspecifiedです。xfun(&x, &y)

式の評価で不特定の結果が得られることは、プログラムに未定義の動作があることを意味しないことに注意してください。むしろ、可能な結果の有限集合のどれがその式の評価によって生成されるを知ることができないことを意味します。

ここで標準を解釈するのは非常に難しい場合があります(実際、元の回答では、私はそれを間違った方法で解釈していました-気づいてくれたJerry Coffinに感謝します)。

これが難しい理由を理解するために、C++11 標準の段落 1.9/15 の最初の部分を考えてみましょう。

特に明記されていない限り、個々の演算子のオペランドおよび個々の式の部分式の評価は unsequencedです。[...] 演算子のオペランドの値の計算は、演算子の結果の値の計算の前に並べられます。スカラー オブジェクトに対する副作用が、同じスカラー オブジェクトに対する別の副作用、または同じスカラー オブジェクトの値を使用した値の計算に対して順序付けされていない場合、動作は undefinedです。

たとえば、次のような 2 つのサブ式の合計を計算する式があるとします (consideringoperator +はここではオーバーロードされていません)。

e1 + e2

の評価でe1特定のスカラーの値が使用され、sの評価でe2その値に副作用がある場合、動作は未定義です。たとえば、次の評価:

(i + i++)

上記の文により、未定義の動作が発生します。

ただし、状況は異なります。後の同じ段落では、次のように指定されています。

関数を呼び出すとき (関数がインラインであるかどうかにかかわらず)、[...] 呼び出された関数の本体の実行の前後に特に順序付けされていない呼び出し関数 (他の関数呼び出しを含む) のすべての評価は、呼び出された関数の実行に関して不定に順序付けられます。

これは、評価される式が次のようになっている場合を意味します。

i + f(i)

そしてf(i)増加iすると、動作は未定義ではなくなり、未指定のみになります。言い換えれば、コンパイラはiandf(i)を任意の順序で評価できますが、可能な結果はこれらの可能な評価の 1 つの結果にすぎません。

一方、動作が定義されていない場合、考えられる結果は何でもありました (クラッシュから、期待どおりの動作、コンソールへの奇妙なメッセージの出力などに至るまで)

于 2013-05-28T15:16:30.130 に答える
1

あなたのコードには未指定の結果があります。

式内のサブ式の評価順序は指定されていません。したがって、 ではx + y + fun(&x, &y) + x;x関数呼び出しの外側で取得する値はx、関数呼び出しの前または関数呼び出しの後の の値である可能性があります。そのx外側の 2 つの異なる場所にあるため、1 つは関数呼び出しの前から、もう 1 つは関数呼び出しの後から、または両方が前から、または両方が後からである可能性があります。

関数に入る前と関数を出る前にシーケンス ポイントがあるため、関数のx外側の値の使用と関数内の値の変更の間にシーケンス ポイントがあります。したがって、あなたの行動は定義されていますが、未指定です。

C++11 の時点で、「シーケンス ポイント」という用語は標準から削除され、「前にシーケンスされた」、「後にシーケンスされた」、「に関してシーケンスされていない」などの用語が使用されるようになりました。その過程で、以前は指定されていなかったいくつかの場所で順序が指定されました。以前に指定されたシーケンス (関数の入口と出口のシーケンス ポイントなど) が削除されたとは思いません。つまり、私が完全に間違っていない限り、この場合の状況は変わりません。

于 2013-05-28T15:20:51.693 に答える
1

以下に示すコードを検討してください。

x=10;
val=x+f(&x);


void f(int *a)
{
  *a=*a+10;
}

オペランドの左側が最初に評価されるか右側が評価されるかは、C++ 標準では定義されていません。したがって、val左側が最初に評価される場合、変数の値は 30 になり、右側が最初に評価される場合、値は 40 になります。コードでも同じことが起こります。

于 2013-05-28T15:21:43.403 に答える