私は Stroustrup の本「The C++ Programming Language 4th edition」を読んでいて、割り当てのオーバーフローに関して 3 つの質問があります (特に、本が示すように、signed/unsigned char に対して)。まず、標準の 5/4 パラグラフによると:
式の評価中に、結果が数学的に定義されていないか、その型の表現可能な値の範囲内にない場合、動作は undefinedです。
(宛先変数が符号なしの場合を除きます - そのような場合、結果は明確に定義されます)。しかし、この定義は割り当てにも関係しますか?
私の意見では、この本には多くの反対の声明があり、すべて第6章にあります.最初のものは前述の段落に対応していますが、次のコメントはそうではありません:
3 つのタイプの変数は、
char
相互に自由に割り当てることができます。ただし、大きすぎる値を a に代入することsigned char
はまだ定義されていません。例えば:void g(char c, signed char sc, unsigned char uc) { c = 255; //implementation-defined if plain chars are signed and have 8 bits c = sc; //OK c = uc; //implementation-defined if plain chars are signed and if uc's value is too large sc = uc; //implementation-defined if uc's value is too large uc = sc; //OK: conversion to unsigned sc = c; //implementation-defined if plain chars are unsigned and if c's value is too large uc = c; //OK: conversion to unsigned }
最初の質問: 大きすぎる値を割り当てることは UB であるため、なぜコメントはそれが実装定義であると言っているのですか?
次に、次の例があります。
具体的には、a
char
が 8 ビットであると仮定します。signed char sc = -160; unsigned char uc = sc; //uc == 116 (because 256-160==116) cout << uc; //print 't'
2 番目の質問: 最初の割り当てがおそらく UB であるという事実は別として、著者が 116 を導き出すために正確に使用した公式は何ですか? 私のテストでuc
は、96 の値を取得しました。
そして最後の引用:
整数は別の整数型に変換できます。宛先が の場合
signed
、宛先タイプで表現できる場合、値は変更されません。それ以外の場合、値は実装定義です。
signed char sc = 1023; //implementation-defined
妥当な結果は 127 と -1 です。
3 番目の質問: 繰り返しますが、これが以前に UB について言われたことに反するという事実は別として、なぜ可能な結果が 127 と -1 になるのでしょうか? 1 の補数と 2 の補数に関係があると思いますが、具体的にどのような公式が使われているのでしょうか?