5

この質問は、別のSO質問の結果です。

サンプルコード

#include <iostream>

int main()
{
    unsigned long b = 35000000;
    int i = 100;
    int j = 30000000;
    unsigned long n = ( i * j ) / b; // #1
    unsigned long m = ( 100 * 30000000 ) / b; // #2
    std::cout << n << std::endl;
    std::cout << m << std::endl;
}

出力

85
85

このコードをでコンパイルするとg++ -std=c++11 -Wall -pedantic -O0 -Wextra、次の警告が表示されます。

9:28: warning: integer overflow in expression [-Woverflow]

質問

  1. 中間結果がに適合しないため、私はそれを考えて未定義の動作#1を呼び出すのは正しいですか?または、私が見ている出力は明確に定義されていますか?#2100 * 30000000int

  2. で警告しか表示されないのはなぜ#2ですか?

4

5 に答える 5

3

unsigned longはい、それは未定義の動作であり、64ビットタイプの場合、通常、得られる結果は¹異なります。

¹これはUBであるため、保証はありません。

于 2012-09-19T04:22:26.843 に答える
2

1)はい、それは未定義の動作です。

2)#1には変数(定数ではない)が含まれるため、コンパイラーは一般にオーバーフローするかどうかを知りません(ただし、この場合はオーバーフローし、警告しない理由はわかりません)。

于 2012-09-19T04:24:58.010 に答える
2

中間結果

はい、これは未定義の動作です。すぐそこに立ち寄ったらどうしますreturn mか?コンパイラーはポイントAからポイントBに移動する必要があり、その計算を行うことによってコンパイラーに移動するように指示しました(これは不可能です)。コンパイラーは、オーバーフローが発生しないようにこのステートメントを最適化することを選択できますが、私が知る限り、標準ではオプティマイザーが何もする必要はありません。

それらが変数であるのになぜエラーがないのですか?

あなたは明示的にgccにまったく最適化しないように指示しているので( )、私の仮定はそれがその時点での値を-O0知らないということです。通常、定数畳み込みのために値を学習しますが、私が言ったように、最適化しないように指示しました。ij

これを再実行してもまだ言及されていない場合は、オプティマイザーが実行される前にこの警告が生成される可能性もあるため、このステップで定数畳み込みを実行するのは賢明ではありません。

于 2012-09-19T04:26:31.100 に答える
1

コンパイラはオペランドの値を知っているため、2つの警告が表示されます。/bどちらもunsignedlongを使用しているため、出力は正しいです。除算される一時的な値は、データ型のb範囲以上( i * j )( 100 * 30000000 )あるか、分割される値と同じデータ型の範囲を持つCPUレジスタに格納されている必要bがありintます。一時的な結果がであるint場合、bはulongであるためです。 、intをulongで除算することはできません。一時的な値は、ulongに格納されます。

オーバーフローした場合は未定義の動作ですが、その場合はオーバーフローしません

b同じ構造で、に変更するだけのプログラムでは、int.sコードに2行しかありません。

cltd 
idivl   (%ecx) 

to b = int

movl    $0, 
%edx divl   (%ecx)

to b = unsigned long、

idivlは符号付き除算を実行し、値を符号付き除算として格納します
divlは符号なし除算を実行し、値を符号なしとして格納します

そうです、演算はオーバーフローします。除算演算のため、出力は正しいです。

idivlとdivlの違いは何ですか?

https://stackoverflow.com/a/12488534/1513286

于 2012-09-19T05:13:58.420 に答える
0

5/4に関しては、結果は未定義の動作です。

ただし、型をunsignedに変更した場合(定数の場合はu接尾辞を追加するだけ)、値が適合するだけでなく、3.9.1 / 4によると、算術はモジュロ算術になり、結果はより大きな中間体に対しても完全に定義されます。タイプに適合しない値。

于 2012-09-19T05:38:50.470 に答える