1. ホーム
  2. c

aが初期化されていない場合、a^aやa-aは未定義の動作なのでしょうか?

2023-08-25 05:47:26

質問

このプログラムを考えてみましょう。

#include <stdio.h>

int main(void)
{
    unsigned int a;
    printf("%u %u\n", a^a, a-a);
    return 0;
}

未定義の動作なのでしょうか?

表面上は a は初期化されていない変数です。つまり、未定義の挙動を指しているわけです。しかし a^aa-a0 のすべての値に対して a というのは、少なくとも私はそう思っています。動作がうまく定義されていることを主張する何らかの方法がある可能性はありますか?

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

C11で。

  • 6.3.2.1/2 によれば、以下の場合、明示的に未定義です。 a はそのアドレスが取られることはありません (以下引用)
  • トラップ表現(アクセスするとUBが発生する)である可能性があります。6.2.6.1/5:

ある種のオブジェクト表現は、オブジェクト型の値を表す必要はありません。

Unsigned intはトラップ表現を持つことができます(例えば、15精度ビットと1パリティビットを持つ場合、アクセスする a にアクセスすると、パリティ障害を引き起こす可能性があります)。

6.2.4/6では、初期値として 不定 であり、3.19.2におけるその定義は 不特定値またはトラップ表現 .

さらに:C11 6.3.2.1/2 で、Pascal Cuoq によって指摘されたように。

lvalueが自動保存期間のオブジェクトを指定する場合、そのオブジェクトはレジスタ保存クラスで宣言された可能性があります(アドレスが取られたことはありません)。 レジスタ保存クラスで宣言された(そのアドレスが取られたことのない)自動保存期間のオブジェクトを指定し、そのオブジェクトが初期化されていない(そのアドレスが取られたことのない)場合。 が初期化されていない(イニシャライザで宣言されておらず、使用前に代入が行われていない)場合、動作は次のようになります。 の場合、その動作は未定義です。

これは文字型に対する例外を持たないので、この節は前の議論に優先するように見えます; accessing x にアクセスすることは、たとえトラップ表現が存在しなくても、即座に未定義となります。この節は は C11 に追加されました。 は、実際にレジスタのトラップステートを持っている Itanium CPU をサポートするために追加されました。


トラップ表現がないシステム。 しかし、もし私たちが &x; を投げることで、6.3.2.1/2 の反論はもはや適用されず、トラップ表現を持たないことが知られているシステム上にいる場合はどうでしょうか。 その場合、その値は 未指定値 . の定義は 不特定値 の定義は少し曖昧ですが、3.19.3では以下のように明確化されています。 DR 451 と結論付けています。

  • 説明された条件下で初期化されていない値は、その値を変更するように見えることがあります。
  • 不確定な値に対して行われる操作は、結果として不確定な値を持つことになります。
  • ライブラリ関数は、不定値で使用された場合、未定義の挙動を示すようになります。
  • これらの回答は、トラップ表現を持っていないすべての型に適切です。

この解答のもとでは int a; &a; int b = a - a; の結果は b はまだ不確定な値を持っています。

不定値がライブラリ関数に渡されない場合、我々はまだ未定義の動作の領域にいることに注意してください(未定義の動作ではありません)。結果は奇妙なものになるかもしれません、例えば if ( j != j ) foo(); は foo を呼び出すことができますが、悪魔は鼻腔に鎮座したままでなければなりません。