1

私がこれを行う場合、JavaとC#で:

int i=1;
int j= i++ + i;

j は 3 です。つまり、1+2 に変換され、加算の前に i がインクリメントされます。

ただし、C では j は 2 です。つまり、1+1 に変換されてから i がインクリメントされます。

C と Java/C# の内部メカニズムによって、式とは何かという違いが生じる原因は何ですか?

(ポストフィックスも同様。Java/C# は 4 になり、C は 3 になります。)

ありがとう。

ところで、最初は C の答えだと思っていたので、Java/C# の結果に戸惑いました。

4

4 に答える 4

5

副作用が発生するタイミングを正確に指定する Java や C# とは異なり、C では次のシーケンス ポイントの前に副作用のある式を使用することは禁止されています。式が C で異なる結果を生成するだけでなく、未定義の動作でもあります。

于 2013-02-20T13:45:15.670 に答える
2

C言語標準の2011年のドラフトから:

6.5 式

...
2 スカラー オブジェクトに対する副作用が、同じスカラー オブジェクトに対する別の副作用または同じスカラー オブジェクトの値を使用した値の計算と比較して順序付けられていない場合、動作は未定義です。式の部分式に複数の順序付けが許可されている場合、いずれかの順序付けでそのような順序付けされていない副作用が発生した場合の動作は未定義です。84)

3 演算子とオペランドのグループ化は、構文によって示されます。85)後で指定された場合を除き、部分式の副作用と値の計算は順不同です。86)
84) この段落は、次のような未定義のステートメント式をレンダリングします。
    i = ++i + 1;
    [i++] = 私;
許可しながら
    私 = 私 + 1;
    a[i] = i;

85) 構文は、式の評価における演算子の優先順位を指定します。これは、この副次句の主要な副次句の順序と同じであり、優先順位が最も高くなります。したがって、たとえば、2 項 + 演算子 (6.5.6) のオペランドとして許可される式は、6.5.1 から 6.5.6 で定義された式です。例外は、単項演算子 (6.5.3) のオペランドとしてのキャスト式 (6.5.4)、および演算子の次のペアのいずれかに含まれるオペランドです: グループ化括弧 () (6.5.1)、下付き括弧 [] (6.5) .2.1)、関数呼び出し括弧 () (6.5.2.2)、および条件演算子 ? : (6.5.15)。各主要な副次句内では、演算子の優先順位は同じです。左結合性または右結合性は、各節で説明されている式の構文によって示されます。

86) プログラムの実行中に 2 回以上評価される式では、その部分式の順序付けされていない評価および不定に順序付けられた評価は、異なる評価で一貫して実行される必要はありません。

より大きな式に対しての副作用i++が適用される順序i++ + i規定されていません。2 つの操作は相互に順序付けされていません。が評価された直後に副作用が適用されたi++場合、1 + 2 の結果が得られます。副作用が加算の後まで延期された場合、1 + 1 の結果が得られます。

標準の古いバージョンは少し明確でした。オブジェクトは、シーケンス ポイント間の式の評価によって最大 1 回変更された値を持つことができ、式の以前の値は、格納される新しい値を決定するためにのみ使用されます。

コンパイラがこれらの問題を検出して診断を発行する必要がないように、動作は未定義i++ + iのままになっています (検出するのは簡単ですが、検出がはるかに難しい、この問題のはるかに微妙なバリエーションがあります)。言語定義に関する限り、どちらの結果も「正しい」ものです。

于 2013-02-20T14:41:49.767 に答える
2

C では、このメカニズムは、親しみを込めてUndefined behavior、または「UB」として知られている、コンパイラ作成スキルの微調整されたお祝いです。

言い換えれば、コードは未定義の動作をトリガーすることが事前にわかっているため、C の答えを提供できる人は誰もいません。何が起きてもおかしくない、「正しい」も「間違っている」もありません。

于 2013-02-20T13:44:52.090 に答える
-3

C では、現在の操作が完了した後にポスト インクリメント/デクリメントが実行されます。この例では、i++ + i; 追加が完了すると、i がインクリメントされます。

于 2013-02-20T13:48:05.247 に答える