2016-04-10 17 views
3

コードは次のとおりです。私はそれをVS、clang ++、G ++でテストしました。それらのすべては、1 << 321 << i(iは32)が異なることを示しています。私は組み立てを見た。コンパイル時にコンパイラが1 << 32の結果を計算するようです。この不一致はバグでなければならないと思うし、それはC++のもう一つの未定義の動作だと思う。`1 << 32`と` int i = 32;なぜですか? 1 << i`は別の結果を表示しますか?バグか機能ですか?

#include <iostream> 

int main(int argc, char *argv[]) 
{ 
    std::cout << (1 << 32) << std::endl; 
    int i = 32; 
    std::cout << (1 << i) << std::endl; 
    return 0; 
} 

結果:

clang++: 
1 << 32:73832 
1 << i:1 
g++: 
1 << 32:73832 
1 << i:1 
+9

違う結果を示していますが、これらの結果は表示されません。 – ForceBru

+0

[警告](http://coliru.stacked-crooked.com/a/277b5da2e9464284)を確認してください。 –

+0

@πάνταῥεῖ私は警告を受けた。私はちょうど '(1 << i)が(1 << 32)と異なる理由を知りたいだけです。私は彼らが同じであるべきだと思います。 – Yyao

答えて

3

C++標準は、E1 << E2

値がE1左シフトE2ビット位置であると言います。空白のビットはゼロで埋められます。 E1unsignedタイプがある場合、結果の値はE1×2^E2であり、結果タイプで表現可能な最大値の1を法として減少します。そうでない場合、E1signedタイプで負でない値を持ち、E1×2^E2が結果タイプで表現可能であれば、結果の値です。 この動作は定義されていません

、次いで

結果のタイプが促進左オペランドのものです。 右オペランドが負の場合、またはプロモートされた左オペランドのビットの長さ以上の場合、動作は未定義です。

この場合、何か良いとは限りません。

8

のstd :: COUT < <(1 < < 32)< <はstd :: ENDL。

intがシステムで4バイトの場合、これはundefined behaviorです。標準(シフト演算子に関するセクション)から:

結果のタイプは、昇格された左オペランドのタイプです。右側のオペランドが負の場合は、 の動作は定義されていません。以上 昇格された左オペランドのビット長より長いか等しい。

2

<<に対する両方のオペランドは、intsであり、したがって結果はintです。 intが最大32ビット幅の場合、両方の場合で符号付き整数オーバーフローが発生します。符号付き整数オーバーフローは、常にCおよびC++の両方で未定義の動作をしています。

はしかし、多くの人が誤って未定義の動作が結果は、いくつかの「未指定int」であるか、そのプラットフォーム上という結果が1 << 32 (mod 2³²)であることを意味することを信じています。実際には、64ビットのプラットフォームでは、コンパイラは32ビット計算に64ビットレジスタを使用する傾向があり、適合するプログラムで計算がオーバーフローすることはないことを知っているため、未定義のビヘイビアの場合、実際の結果は値それは32ビット変数にも適合しません!

関連する問題