2012-04-02 10 views
5

質問タイトルが読み取ると、2^31を符号付きおよび符号なし32ビット整数変数に割り当てると、予期しない結果が得られます。ここで符号なしおよび符号なし32ビット整数変数に2^31を代入した後の奇妙な結果

は、私は何が起こっているのか確認するために作られた、(C++中)のショートプログラムです:

#include <cstdio> 
using namespace std; 

int main() 
{ 
    unsigned long long n = 1<<31; 
    long long n2 = 1<<31; // this works as expected 
    printf("%llu\n",n); 
    printf("%lld\n",n2); 
    printf("size of ULL: %d, size of LL: %d\n", sizeof(unsigned long long), sizeof(long long)); 
    return 0; 
} 

ここでは出力です:

MyPC/# c++ test.cpp -o test 
MyPC/# ./test 
18446744071562067968  <- Should be 2^31 right? 
-2147483648    <- This is correct (-2^31 because of the sign bit) 
size of ULL: 8, size of LL: 8 

私はそれに、別の機能p()を追加しました:

void p() 
{ 
    unsigned long long n = 1<<32; // since n is 8 bytes, this should be legal for any integer from 32 to 63 
    printf("%llu\n",n); 
} 

コンパイルと実行時に、これは混乱しますさらに私はさらに:

コンパイラは左シフトカウントが大きすぎると不満を持ちますか? sizeof(unsigned long long)は8を返します。したがって、2^63-1はそのデータ型の最大値です。

それは多分、N * 2とn < < 1、常に同じように動作し、私はこの試みたしていないことを私を襲った:これは、のように2^63の正確な値を与える

void s() 
{ 
    unsigned long long n = 1; 
    for(int a=0;a<63;a++) n = n*2; 
    printf("%llu\n",n); 
} 

を出力は9223372036854775808です(私はそれをpythonで検証しました)。しかし、左のたわごとをして何が間違っていますか?ウィキペディア

値がオーバーフローされていない -

(値がオーバーフローしない提供)

nだけ左シフト演算が2 N を乗算と等価です値が2^63(すべてのビットが設定されている)なので、マイナス記号だけが表示されます。

私はまだ左シフトで何が起こっているのか理解できません。だれでも説明してください。

PS:(それは場合に役立ちます)このプログラムは、このライン上でLinuxのミントを実行している32ビットシステムで

+0

を使用これは、長い 'unsigned long型のn = 1ULL << 31でなければなりません;' – kirilloid

+0

神!これは簡単でしたか?なぜ私はそれを考えなかったのですか?とにかく、はい1ULL << 31は動作します。ほんとありがと! – Rushil

答えて

10

を実行しました:

unsigned long long n = 1<<32; 

問題がリテラル1がタイプintであるということですおそらくわずか32ビットです。したがって、シフトはそれを限界から押し出すでしょう。

大きなデータ型に格納しているというだけで、式のすべてがその大きなサイズで行われるわけではありません。 1は(それがintある)正しい型を持っていないため

unsigned long long n = (unsigned long long)1 << 32; 
unsigned long long n = 1ULL << 32; 
+0

最後の提案に関して:**お願いします**型名の帽子を使用してください。多くのフォントでは、 '1ll'と' 111'を区別することは不可能ではないにしても困難です。 '1LL'は明瞭で曖昧ではない(そして' 0'で問題を作り出すために 'O'の後ろにはない)。 –

+0

提案がありました。 :) – Mysticial

5

1 << 32が失敗した理由は次のとおりです。

だから、それを修正するために、あなたはそれをキャストするか、unsigned long longリテラルにするのいずれかが必要です。コンパイラは実際に代入自体が起こる前に変換マジックを実行しないので、1 << 32intを使用して評価され、オーバーフローに関する警告を出します。

long longunsigned long longの代わりにそれぞれ1LLまたは1ULLを使用してみてください。

3

行オーバーフローで

unsigned long long n = 1<<32; 

結果、リテラル1種類intであるためには、そう1 << 32はまた、ほとんどの場合、32ビット整数です。

ライン

unsigned long long n = 1<<31; 

も同様の理由で、オーバーフローします。 1のタイプはsigned intなので、実際にはその値は31ビット、符号は1ビットしかありません。したがって、1 << 31をシフトすると、値ビットがオーバーフローして-2147483648となり、符号なしlong longに変換されます。これは18446744071562067968です。変数を検査して変換すると、デバッガでこれを確認できます。

だから

unsigned long long n = 1ULL << 31; 
関連する問題