[C++] ポストインクリメント演算子の動作


Answers

これは不特定の動作ではなく、実際には未定義の動作です。

はい、引数評価の順序は指定されていませんが、読み込みが新しい値を計算することのみを目的としている場合を除いて、介在するシーケンスポイントなしで単一の変数を読み込んで変更することは未定義です。 f(test,test++)未定義の振る舞いです: testは1つの引数に対して読み込まれ、もう一方の引数は変更されます。 あなたが関数に変更を移したら、あなたは大丈夫です:

int preincrement(int* p)
{
    return ++(*p);
}

int test;
printf("%d %d\n",preincrement(&test),test);

これは、 preincrementへの進入および退出時にシーケンスポイントが存在するため、コールは単純な読み取りの前または後に評価する必要があるためです。 今注文は不明です。

コンマ演算子はシーケンスポイントを提供することに注意してください。

int dummy;
dummy=test++,test;

大丈夫です---インクリメントは読み込みの前に起こるので、 dummyは新しい値に設定されます。

Question

可能な重複:
C、C ++、Java、およびC#における演算子の前後のインクリメント

ここにテストケースがあります:


void foo(int i, int j)
{
   printf("%d %d", i, j);
}
...
test = 0;
foo(test++, test);

私は "0 1"の出力を得ることを期待しますが、私は "0 0"を得ます。




他人が言ったことを繰り返すために、これは不特定の振る舞いではなく、むしろ未定義です。 このプログラムは合法的に何も何も出力せず、どんな値でも残したり、あなたの上司に侮辱的なメールを送ります。

実際には、コンパイラの作者は通常、書くのが最も簡単な処理を行います。これは一般的にプログラムがnを1〜2回フェッチし、関数を呼び出し、いつかインクリメントすることを意味します。 これは、考えられる他の行動と同様、標準によればまあまあです。 コンパイラやバージョン間、または異なるコンパイラオプション間で同じ動作が期待される理由はありません。 なぜなら、同じプログラム内の2つの異なるが類似している例が一貫してコンパイルされなければならない理由はありませんが、それは私が賭ける方法です。

要するに、これをしないでください。 好奇心が強い場合は別の状況下でテストしてください。しかし、正確な結果が1つしかないと思わないでください。




コンパイラは、あなたが期待する順序で引数を評価していないかもしれません。




それは "不特定の動作"ですが、実際にはCコールスタックが指定されている方法では、ほとんど常に0、0、決して1、0と見なされます。

誰かが指摘したように、VCによるアセンブラ出力は、最初にスタックの最も右のパラメータをプッシュします。 これは、C関数呼び出しがアセンブラでどのように実装されるかです。 これは、Cの「無限パラメータリスト」機能に対応するためです。 パラメータを右から左の順番で押すと、最初のパラメータがスタックの一番上の項目であることが保証されます。

printfの署名を取る:

int printf(const char *format, ...);

これらの省略記号は、未知数のパラメータを示す。 パラメータが左から右にプッシュされた場合、フォーマットはスタックの最下部にあり、そのサイズはわかりません。

C(およびC ++)では、パラメータが左から右に処理されていることがわかっているので、関数呼び出しを解析して解釈する最も簡単な方法を判断できます。 パラメータリストの最後に移動し、複雑なステートメントを評価しながらプッシュを開始します。

しかし、ほとんどのCコンパイラが "Pascal style"関数を解析するオプションを持っているので、これでもあなたを救うことはできません。 これは、関数のパラメータが左から右の方法でスタックにプッシュされるということです。 たとえば、printfがPascalオプションでコンパイルされた場合、出力は1、0になります(しかし、printfは楕円を使用するため、コンパイルできないと思います)。




ええと、OPが一貫性のために編集されたので、答えと同期していません。 評価の順序に関する基本的な答えは正しい。 しかし、特定の可能な値はfoo(++ test、test)と異なります。 場合。

++テスト渡される前にインクリメントれるため、最初の引数は常に1になります。2番目の引数は評価順に応じて0または1になります。