符号付き整数オーバーフローはC ++でも未定義の動作ですか?


82

ご存知のように、符号付き整数オーバーフローは未定義の動作です。しかし、C ++ 11のcstdintドキュメントには興味深いものがあります。

幅がそれぞれ正確に8、16、32、64ビットで、パディングビットがなく、負の値に2の補数を使用する符号付き整数型(実装が型を直接サポートしている場合にのみ提供)

リンクを見る

そして、ここに私の質問があります:標準では、、、および負の数は2の補数であると明示的に述べられているint8_tのでint16_t、これらのタイプのオーバーフローは未定義の動作ですか?int32_tint64_t

編集私はC ++ 11とC11標準をチェックしました、そしてここに私が見つけたものがあります:

C ++ 11、§18.4.1:

ヘッダーは、C標準の7.20と同じように、すべての関数、タイプ、およびマクロを定義します。

C11、§7.20.1.1:

typedef名はintN_t、幅N、パディングビットなし、2の補数表現の符号付き整数型を指定します。したがって、int8_tは、正確に8ビットの幅を持つそのような符号付き整数型を示します。


14
C ++の唯一の主要なドキュメントが標準であることを忘れないでください。CppReferenceのようなウィキでさえ、他のすべては二次情報源です。それが間違っているという意味ではありません。完全に信頼できるわけではありません。
ニコルボーラス2013

私はそれがUBであることを期待します、Cでこれらのタイプの免除はありません、私はC ++がなぜそれを追加するのか分かりません。
ダニエルフィッシャー


3
私は少し混乱しています:「それぞれ正確に8、16、32、64ビットの幅の符号付き整数型で、パディングビットがなく、負の値に2の補数を使用している」という文の動詞はどこにありますか(実装が直接サポートしている場合にのみ提供されます)タイプ)?" 少し欠けていますか?どういう意味ですか?
YSC 2015

C ++ 11は、C11ではなくC99に基づいています。しかし、これはとにかく重要ではありません
LF

回答:


80

これらのタイプのオーバーフローは未定義の動作ですか?

はい。C ++ 11標準のパラグラフ5/4による(一般的な式に関して):

式の評価中に、結果が数学的に定義されていないか、そのタイプの表現可能な値の範囲内にない場合、動作は未定義です。[...]

これらの符号付き型に2の補数表現が使用されているという事実は、これらの型の式を評価するときに2 ^ nを法とする算術演算が使用されることを意味するものではありません。

一方、符号なし算術に関しては、規格は明示的に次のように指定しています(パラグラフ3.9.1 / 4)。

符号なし整数は、宣言されunsigned算術モジュロの法則に従わなければならない2 ^ nはここでnは整数のその特定のサイズの値表現のビット数であります

これは、符号なし算術演算の結果が常に「数学的に定義され、結果が常に表現可能な範囲内にあることを意味します。したがって、5/4は適用されません。脚注46はこれを説明しています:

46)これは、結果の符号なし整数型で表現できない結果が、結果の符号なし整数型で表現できる最大値より1大きい数を法として減少するため、符号なし算術がオーバーフローしないことを意味します。


1
この段落は、符号なしオーバーフローが定義されていないことも意味しますが、定義されていません。
Archie

8
@Archie:符号なしの値は符号なしの範囲を法として定義されているため、実際にはそうではありません。
軌道上でのライトネスレース2013年

3
@Archie:明確にしようとしましたが、基本的にはLightnessRacesinOrbitから回答を得ました
Andy Prowl 2013

1
符号なしオーバーフローが定義されているかどうかは、モジュロ計算のために発生しないかどうかは実際には問題ではありません...
アコンカグア2018

1
結果が「数学的に定義」されていない(特にゼロによる除算)符号なし演算があるため、おそらくあなたの言い回しはその文で意図したものとはまったく異なります。結果が数学的に定義されている場合、 C ++でも定義されているというITYM 。
TobySpeight19年

22

2の補数表現を使用するように型が定義されているからといって、その型の算術オーバーフローが定義されることはありません。

符号付き算術オーバーフローの未定義の動作は、最適化を可能にするために使用されます。例えば、コンパイラがあればそれを想定することができa > b、その後a + 1 > bも。これは、にa + 1ラップアラウンドする可能性があるため、2番目のチェックを実行する必要がある符号なし演算には当てはまりません0。また、一部のプラットフォームでは、算術オーバーフロー時にトラップ信号を生成できます(例:http//www.gnu.org/software/libc/manual/html_node/Program-Error-Signals.htmlを参照)。標準では、これを引き続き許可しています。


5
多くの人がトラップの可能性についてもっと「心配」していることは注目に値するかもしれませんが、コンパイラの仮定は実際にはもっと陰湿です(実装定義の動作とは異なり、実装定義の動作と未定義の動作の間にカテゴリがあったらいいのにと思う理由の1つです)一貫した文書化された方法で何かを行うために特定の実装が必要な場合、何かの結果として発生する可能性のあるすべてを指定する実装を必要とする「実装に制約のある」動作が必要です(仕様には未定義の動作を明示的に含めることができますが.. 。
supercat

3
...実装は、実用的な場合はより具体的にすることが推奨されます)。2の補数が自然に「ラップ」するハードウェアでは、ラップされた整数の結果が整数オーバーフローなしで実行しようとする多くの命令を実行することを望むコードの理にかなった理由はありません。ハードウェアは1つまたは2つの命令で実行できます。 。
スーパーキャット2015

1
@supercat実際、ラップされた結果が必要なコードは、(2の補数CPUで)対応する符号なし型にオペランドをキャストして演算を実行できます(その後、キャストバックして実装定義の値を取得します)。これは、加算、減算、乗算で機能します。 。唯一の問題は、除算、モジュロ、およびなどの関数にありabsます。それが機能するときのそれらの操作のために、それは署名された算術より多くの指示を必要としません。
ルスラン

@Ruslan:コードが正確にラップされた結果を必要とする場合、unsignedへのキャストは醜いですが、必ずしも余分なコードを生成するとは限りません。より大きな問題は、「潜在的に興味深い」候補をすばやく特定する必要があるコードにあります。これは、ほとんどの時間を、興味のない候補を拒否することに費やします。コンパイラに符号付き整数値で余分な精度を任意に保持または破棄する自由を与えるが、整数型へのキャストバックがそのような精度を切り捨てる必要がある場合、オーバーフローUBを作成することによって達成される有用な最適化のほとんどが可能になります、...
スーパーキャット2016年

...ただし、正確な折り返しが必要なコードで2つではなく1つのキャストを使用できるようにし(たとえば、折り返した(int)(x+y)>z結果を比較する)、x+y>zコードが0または1を生成することが許容される場合にプログラマーが記述できるようにします。他の副作用がなければ、オーバーフローの。0または1のいずれかが同等に受け入れられる結果である場合、プログラマーにどちら(long)x+y>zかで(int)((unsigned)x+y)>zはなくそれを記述させるか、コンパイラーが特定のコンテキストで後者の関数のどちらか安い方を選択できるようにします[それぞれが場合によっては安くなります]。
スーパーキャット2016年

1

私はそう思うだろう。

標準ドキュメント(4ページおよび5ページ)から:

1.3.24未定義の振る舞い

この国際規格が要件を課していない行動

[注:この国際規格で動作の明示的な定義が省略されている場合、またはプログラムが誤った構成または誤ったデータを使用している場合、未定義の動作が予想される場合があります。許容される未定義の動作は、予測できない結果で状況を完全に無視することから、翻訳またはプログラムの実行中に環境に特徴的な文書化された方法で動作すること(診断メッセージの発行の有無にかかわらず)、翻訳または実行の終了(発行あり)にまで及びます。診断メッセージの)。多くの誤ったプログラム構成は、未定義の動作を引き起こしません。それらは診断する必要があります。-エンドノート]

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.