2012-04-02 26 views
5

पर 2^31 असाइन करने के बाद अजीब परिणाम प्रश्न शीर्षक के रूप में, हस्ताक्षर किए गए और हस्ताक्षरित 32-बिट पूर्णांक चर के लिए 2^31 असाइन करने से एक अप्रत्याशित परिणाम मिलता है।एक हस्ताक्षरित और हस्ताक्षरित 32-बिट पूर्णांक चर

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() कहा, यह करने के लिए:

#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; 
} 

यहाँ उत्पादन है:

यहाँ लघु कार्यक्रम (C++ में) है, जो मैं क्या हो रहा है यह देखने के लिए किया जाता है :

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); 
} 

संकलन और चलने पर, यह भ्रमित है डी मुझे और भी अधिक:

MyPC/# c++ test.cpp -o test 
test.cpp: In function ‘void p()’: 
test.cpp:6:28: warning: left shift count >= width of type [enabled by default] 
MyPC/# ./test 
0 
MyPC/

संकलक बाएं शिफ्ट गणना के बारे में शिकायत क्यों करनी चाहिए? sizeof(unsigned long long) 8 लौटाता है, तो इसका मतलब यह नहीं है कि 2^63-1 उस डेटा प्रकार के लिए अधिकतम मान है?

मुझे लगा कि शायद n * 2 और एन < < 1, हमेशा एक ही तरीके से व्यवहार नहीं है, इसलिए मैं इस कोशिश की:

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

इस रूप में 2^63 का सही मूल्य देता है आउटपुट जो 9223372036854775808 है (मैंने इसे पायथन का उपयोग करके सत्यापित किया है)। लेकिन बाएं बकवास करने में क्या गलत है? विकिपीडिया

मूल्य बह निकला नहीं है -

n द्वारा एक बाएं अंकगणित पारी 2 n से गुणा करने के बराबर है

(मूल्य अतिप्रवाह नहीं करता है प्रदान की) , केवल एक ऋण चिह्न दिखाई देगा क्योंकि मान 2^63 है (सभी बिट सेट हैं)।

मैं अभी भी यह पता लगाने में असमर्थ हूं कि बाएं शिफ्ट के साथ क्या चल रहा है, क्या कोई इसे समझा सकता है?

पुनश्च: इस कार्यक्रम के एक 32-बिट सिस्टम चल रहा है लिनक्स टकसाल पर चलाया गया था (है कि अगर मदद करता है)

+0

यह 'होना चाहिए अहस्ताक्षरित लंबे एन = 1ULL << 31;' – kirilloid

+0

भगवान! क्या यह आसान था ?! मैंने इसके बारे में क्यों नहीं सोचा। वैसे भी, हाँ 1ULL << 31 काम करता है। तो धन्यवाद! – Rushil

उत्तर

10

इस लाइन पर:

unsigned long long n = 1<<32; 

समस्या यह है कि शाब्दिक 1 प्रकार int की है - जो शायद केवल 32 बिट्स है। इसलिए बदलाव इसे सीमाओं से बाहर धकेल देगा।

सिर्फ इसलिए कि आप एक बड़े डेटाटाइप में स्टोर कर रहे हैं इसका मतलब यह नहीं है कि अभिव्यक्ति में सब कुछ उस बड़े आकार में किया जाता है।

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

अंतिम सुझाव के संबंध में: ** कृपया ** टाइप डिज़ाइनरों के लिए कैप्स का उपयोग करें। कई फ़ॉन्ट्स के साथ, '1ll' और' 111' के बीच अंतर करना मुश्किल हो सकता है, यदि असंभव नहीं है; '1 एलएल 'स्पष्ट और स्पष्ट है (और' 0' के साथ समस्याएं पैदा करने के लिए प्रत्यय' ओ' नहीं है)। –

+0

सुझाव लिया गया। :) – Mysticial

5

कारण 1 << 32 विफल रहता है, क्योंकि 1 (यह int है) सही प्रकार नहीं है:

तो यह सही करने के लिए, आप या तो यह कास्ट करने के लिए ऊपर या यह एक unsigned long long शाब्दिक बनाने की जरूरत है।असाइनमेंट वास्तव में वास्तव में होने से पहले कंपाइलर कोई कनवर्टिंग जादू नहीं करता है, इसलिए 1 << 32 का मूल्यांकन int अंकगणित का उपयोग करके किया जाता है, जिससे ओवरफ्लो के बारे में चेतावनी दी जाती है।

1LL या 1ULL का उपयोग करने का प्रयास करें, जिसके बजाय क्रमशः long long और unsigned long long प्रकार है।

3

लाइन एक अतिप्रवाह में

unsigned long long n = 1<<32; 

परिणाम, क्योंकि शाब्दिक 1 प्रकार int की है, इसलिए 1 << 32 भी एक पूर्णांक है, जो ज्यादातर मामलों में 32 बिट है।

लाइन

unsigned long long n = 1<<31; 

भी एक ही कारण के लिए overflows,। ध्यान दें कि 1 signed int प्रकार है, इसलिए यह वास्तव में केवल मूल्य के लिए 31 बिट्स और साइन के लिए 1 बिट है। तो जब आप 1 << 31 को स्थानांतरित करते हैं, तो यह मान बिट्स को ओवरफ़्लो करता है, जिसके परिणामस्वरूप -2147483648 होता है, जिसे बाद में एक हस्ताक्षरित लंबे समय तक परिवर्तित किया जाता है, जो 18446744071562067968 है। यदि आप चर का निरीक्षण करते हैं और उन्हें रूपांतरित करते हैं, तो आप इसे डीबगर में सत्यापित कर सकते हैं।

तो का उपयोग

unsigned long long n = 1ULL << 31;