cppreference.com で次の例を見ました
int x; // OK: the value of x is indeterminate
int y = x; // undefined behavior
ここで、x
は初期化されていないため、int y = x;
は未定義の動作です。
だが、
unsigned char c; // OK: the value of c is indeterminate
unsigned char d = c; // OK: the value of d is indeterminate
ここで、unsigned char d = c;
は不確定な動作ですが、unsigned char c;
も初期化されていない変数です。
それで、unsigned char d
の値が不確定なのはなぜですか?
cppreference.com のようなオンライン参照は、ある程度までは問題ありません。しかし、時々エラーや誤解がすり抜けることがあることが知られています。したがって、このような奇妙なことに対処するときは、公式のC++標準に準拠することをお勧めします。
N3936
§8.5イニシャライザー[dcl.init]
12 [...]自動または動的な保存期間を持つオブジェクトのストレージが取得されると、オブジェクトの値は不確定になり、オブジェクトの初期化が実行されない場合、そのオブジェクトはその値が置き換えられるまで不確定な値を保持します(5.17 )。 [...]評価によって不確定な値が生成された場合、次の場合を除いて、動作は定義されていません。
符号なしの狭い文字タイプ(3.9.1)の不確定な値が、次の評価によって生成された場合
[...]
符号なしナロー文字タイプへのキャストまたは変換のオペランド(4.7、5.2.3、5.2.9、5.4)
[...]
その場合、操作の結果は不確定な値になります。
符号なしナロー文字タイプの不確定値が、最初のオペランドが符号なしナロー文字タイプの左辺値である単純代入演算子(5.17)の右オペランドの評価によって生成される場合、不確定値は、によって参照されるオブジェクトの値を置き換えます。左のオペランド
符号なしナロー文字タイプのオブジェクトを初期化する際の初期化式の評価により、符号なしナロー文字タイプの不確定値が生成された場合、そのオブジェクトは不確定値に初期化されます。
例:
int f(bool b) { unsigned char c; unsigned char d = c; // OK, d has an indeterminate value int e = d; // undefined behavior return b ? d : 0; // undefined behavior if b is true }
したがって(私の大きな驚き)、標準はこれをバックアップします。
理由については、最も可能性の高い理由は、標準にも記載されています。
§3.9.1基本的なタイプ[basic.fundamental]
1 [...]符号なしの狭い文字タイプの場合、値表現のすべての可能なビットパターンは数値を表します。 これらの要件は他のタイプには当てはまりません
ちなみに、私はこれが邪悪なインタビュアーによって使用される可能性があることに気づきました。
Q.明確に定義された動作で、オブジェクトの有効な値を未決定の値に変更できますか?はいの場合、どのように?
A。
unsigned char ind;
unsigned char x = 24;
x = ind; // x had a valid value, now x has an indetermined value
参照したページから:不確定な値からの割り当ては未定義の動作です例外
符号なしナロー文字タイプまたはstd :: byteの不確定値が、符号なしナロー文字タイプまたはstd :: byteを持つ別の変数に割り当てられている場合(変数の値は不確定になりますが、動作は未定義ではありません)
これは、デフォルトの初期化ではビットの任意の組み合わせが変数に配置される可能性があり、標準では符号なしの狭い文字タイプがすべての可能なビットパターンで表される値を取ることが保証されているが、他のタイプではそのような保証がないためだと思います。
から リンクされたページ :
デフォルトで取得された不確定値の使用-任意のタイプの非クラス変数の初期化は、次の場合を除いて未定義の動作です[...]。
.。
符号なしナロー文字タイプまたはstd :: byteの不確定値を使用して、別の変数をunsignedナロー文字タイプまたはstd :: byteで初期化する場合。
unsigned char
は符号なしの狭い文字であるため、これはUBが発生しない例外の1つです。
C++に組み込まれたCの2つの関連する便利な機能は、次のとおりです。
オブジェクトは、そこに含まれる個々のバイトをすべてコピーすることでコピーできます。
構造タイプのオブジェクトは、その中のオブジェクトの一部が定義された値を保持していない場合でも、構造全体のコピーまたは個々のバイトのコンテキスト外で未定義の部分またはそのコピーを読み取ろうとしない限り、完全に安全にコピーできます。アクセス。
ほとんどのプラットフォームでは、同じ保証を他のタイプにも拡張できない、または拡張すべきではないという特別な理由はありませんが、C標準の作成者は、すべてのプラットフォームに適用できる保証を定義しようとしただけであり、 C++標準は、単にC++の動作に従いました。