これらの構造が前置増分と後置増分を使用して未定義の動作を行うのはなぜですか? 質問する

これらの構造が前置増分と後置増分を使用して未定義の動作を行うのはなぜですか? 質問する
#include <stdio.h>

int main(void)
{
   int i = 0;
   i = i++ + ++i;
   printf("%d\n", i); // 3

   i = 1;
   i = (i++);
   printf("%d\n", i); // 2 Should be 1, no ?

   volatile int u = 0;
   u = u++ + ++u;
   printf("%d\n", u); // 1

   u = 1;
   u = (u++);
   printf("%d\n", u); // 2 Should also be one, no ?

   register int v = 0;
   v = v++ + ++v;
   printf("%d\n", v); // 3 (Should be the same as u ?)

   int w = 0;
   printf("%d %d\n", ++w, w); // shouldn't this print 1 1

   int x[2] = { 5, 8 }, y = 0;
   x[y] = y ++;
   printf("%d %d\n", x[0], x[1]); // shouldn't this print 0 8? or 5 0?
}

ベストアンサー1

C には未定義の動作という概念があります。つまり、一部の言語構造は構文的には有効ですが、コード実行時の動作を予測することはできません。

私の知る限り、この標準では未定義の動作という概念が存在する理由を明示的に述べていません。私の考えでは、それは単に言語設計者がセマンティクスにいくらかの余裕を持たせたかったからであり、つまり、すべての実装が整数オーバーフローをまったく同じ方法で処理することを要求するのではなく (これは深刻なパフォーマンス コストを課す可能性が非常に高いため)、動作を未定義のままにして、整数オーバーフローを引き起こすコードを記述すると何でも起きるようにしただけであると思います。

では、それを念頭に置いて、なぜこれらの「問題」があるのか​​?言語は、特定のことが原因であると明確に述べている。未定義の動作問題はありません。「すべき」ということはありません。関係する変数の 1 つが宣言されたときに未定義の動作が変わったとしてもvolatile、それは何も証明も変更もしません。それは未定義であり動作について推論することはできません。

最も興味深い例、

u = (u++);

未定義の動作の教科書的な例である(Wikipediaのシーケンスポイント)。

おすすめ記事