2013-05-13 10 views
5

नीचे दिए गए कोड को संकलित करने के बाद, मुझे एक अजीब परिणाम मिला, एक = 1 जबकि बी = 0। क्या कोई इस बात के बारे में बता सकता है कि दृश्य के पीछे क्या चल रहा है?वैरिएबल के साथ बाएं शिफ्ट निरंतर के साथ अलग-अलग परिणाम क्यों उत्पन्न करता है?

#include<iostream> 
using namespace std; 

int main(){ 

    int n=32; 
    int a=1<<n; //turns out a=1 
    int b=1<<32; //turns out b=0 
    cout<<"a="<<a<<endl; 
    cout<<"b="<<b<<endl; 
} 
+0

कोड विकसित करते समय चेतावनियों को हमेशा सक्षम और पढ़ें। उदाहरण के लिए जीसीसी आपको "बाएं शिफ्ट गिनती> = प्रकार की चौड़ाई" बताती है। क्लैंग के '-fsanitize = ...' विकल्प का उपयोग करना भी एक अच्छा विचार है। –

+0

जो कोड आप पोस्ट कर रहे हैं वह स्पष्ट रूप से सी ++ है, लेकिन आप सी के साथ टैग भी करते हैं? दोनों भाषाएं इस तरह के सीमावर्ती मामलों पर विचलित होती हैं, इसलिए उस भाषा के लिए बेहतर प्रश्न पूछें, जिसमें आप वास्तव में रुचि रखते हैं। आम तौर पर हस्ताक्षर किए गए प्रकारों पर शिफ्ट संचालन करना अच्छा नहीं है। –

उत्तर

5

मानक परिभाषित नहीं करता है, या इसके बजाय, यह इसे "अपरिभाषित व्यवहार" के रूप में परिभाषित करता है, मामले में पूर्णांक प्रकार के आकार से परे बाएं शिफ्ट में क्या होता है। [इस अपरिभाषित व्यवहार का कारण यह है कि अलग-अलग हार्डवेयर वही व्यवहार कर सकते हैं या नहीं, उदाहरण के लिए, बाईं ओर 32-बिट शिफ्ट]। जो 86 पर 1 << (32 & 31) में बदल जाता है जो एक ही 1 << 0 के रूप में - -

पहला मामला [कम से कम अनुकूलन के बिना] में, संकलक 1 << 32 की गणना करने के निर्देश उत्पन्न करता है और इस प्रकार आप प्राप्त 1.

दूसरे मामले में, संकलक मूल्य की गणना करेगा, जो एक अतिप्रवाह में बदल जाता है, और शून्य देता है।

यह काफी संभावना है (लेकिन निश्चित नहीं है) कि यदि आप कोड को अनुकूलित करने के लिए कंपाइलर विकल्प बदलते हैं, तो यह दोनों मामलों के लिए शून्य देता है। और यदि आप छोटे बदलावों का एक लूप करना चाहते हैं तो आपको वह व्यवहार प्राप्त करने जा रहे हैं (हालांकि आपको इस तथ्य के साथ "इंटरस्टिंग" व्यवहार मिल सकता है कि संख्या नकारात्मक हो जाती है, इसलिए वास्तव में सभी शिफ्ट परिचालनों के लिए हस्ताक्षरित उपयोग करने के लिए सबसे अच्छा है) ।

5

क्योंकि आप अपरिभाषित व्यवहार का आह्वान कर रहे हैं। इस प्रकार के अस्तित्व की तुलना में अधिक बिट्स को स्थानांतरित करना किसी विशेष व्यवहार के लिए परिभाषित नहीं किया गया है।

http://blog.llvm.org/2011/05/what-every-c-programmer-should-know.html?m=1

बड़े आकार शिफ्ट राशियाँ देखें: 32 या अधिक बिट द्वारा एक uint32_t स्थानांतरण अनिर्धारित रहता है। मेरा अनुमान है कि यह उत्पत्ति हुई है क्योंकि अंतर्निहित विभिन्न CPUs पर शिफ्ट ऑपरेशंस इस के साथ अलग-अलग चीजें करते हैं: उदाहरण के लिए, X86 32 बिट बिट शिफ्ट राशि को 5 बिट्स पर ट्यून करता है (इसलिए 32-बिट्स द्वारा एक शिफ्ट एक शिफ्ट के समान है 0-बिट्स द्वारा), लेकिन पावरपीसी 32 बिट बिट शिफ्ट की मात्रा 6 बिट्स (तो 32 द्वारा एक शिफ्ट शून्य उत्पन्न करता है) को छंटनी करता है। इन हार्डवेयर मतभेदों के कारण, व्यवहार पूरी तरह से सी द्वारा अपरिभाषित है (इस प्रकार पावरपीसी पर 32-बिट्स द्वारा स्थानांतरित करने से आपके हार्ड ड्राइव को प्रारूपित किया जा सकता है, यह शून्य उत्पन्न करने की गारंटी नहीं है)। इस अपरिभाषित व्यवहार को समाप्त करने के की लागत यह है कि कंपाइलर को एक अतिरिक्त ऑपरेशन (जैसे 'और') को परिवर्तनीय बदलावों के लिए उत्सर्जित करना होगा, जो उन्हें सामान्य CPU पर दो गुना महंगा बना देगा।

संबंधित मुद्दे