1. ホーム
  2. c

[解決済み] (なぜ)初期化されていない変数を使用することは未定義の動作なのですか?

2023-02-17 19:05:47

質問

もし、私が

unsigned int x;
x -= x;

というのは明らかです。 x べき がゼロになるはずなのですが、どこを見ても、この式の後に の動作は の値だけでなく、このコードの挙動は未定義であると言っています。 x (の値だけではありません(減算の前まで)。

2つの質問です。

  • 動作 は本当に未定義なのでしょうか?

    (例:準拠したシステムでコードがクラッシュ[または悪化]するかもしれませんか?)

  • もしそうなら なぜ は、Cが 動作 が未定義であることは明らかであるのに x はゼロであるべきであることは明らかなのに?

    すなわち 利点 ここで動作を定義しないことによって与えられる利点は何でしょうか?

明らかに、コンパイラは単に を使用することができます。 を使用することができ、それは意図したとおりに動作するでしょう...そのアプローチの何が問題なのでしょうか?

どのように解決するのですか?

はい、この動作は未定義ですが、多くの人が認識しているのとは異なる理由によるものです。

最初に、ユニット化された値を使用すること自体は未定義の動作ではありませんが、値は単に不確定です。値がたまたま型のためのトラップ表現である場合、これにアクセスすることは UB です。符号なし型はめったにトラップ表現を持たないので、その面では比較的安全でしょう。

動作を未定義にするのは、変数の追加プロパティ、すなわち、それが "で宣言されている可能性があることです。 register で宣言された可能性があること、つまりそのアドレスは決して取得されないということです。このような変数が特別に扱われるのは、"uninitialized" で、型領域内の値に対応しない一種の余分な状態を持つ、実際の CPU レジスタを持つアーキテクチャがあるためです。

編集してください。 規格の該当文言は6.3.2.1p2です。

lvalueが自動保存期間のオブジェクトを指定する場合,それは レジスタ記憶クラスで宣言されたかもしれない(アドレスが取られたことがない)自動記憶期間のオブジェクトを指定する場合 そのアドレスが取得されたことがない)、そのオブジェクトが初期化されていない(イニシャライザで宣言されていない)。 初期化されておらず,使用前に代入が行われていない)場合,動作は未定義となる。 への代入が行われていない)、動作は未定義です。

また、より明確にするために、以下のコードでは はどのような状況でも合法です。

unsigned char a, b;
memcpy(&a, &b, 1);
a -= a;

  • ここでは ab が取られるため、その値は単に 不定です。
  • から unsigned char は決してトラップ表現を持っていません。 不定値は単なる不定値なので unsigned char のどのような値でも が起こり得ます。
  • 最後に a 値を保持する 0 .

編集2 a そして b は値が指定されていません。

3.19.3 不特定値

この国際規格がどの値を選ぶかについて要求していない場合、関連する型の有効な値。 を選択することはできません。