2013-10-28 11 views
30

मुझे यहां बिल्कुल पागल होना चाहिए, लेकिन मेरी मशीन पर gcc 4.7.3 सबसे बेतुका परिणाम दे रहा है।अंकगणित सही शिफ्ट फर्जी परिणाम देता है?

#include <iostream> 

using namespace std; 

int main(){ 
    unsigned int b = 100000; 
    cout << (b>>b) << endl; 
    b = b >> b; 
    cout << b << endl; 
    b >>= b; 
    cout << b << endl; 
    return 0; 
} 

अब, किसी भी संख्या है कि सही अपने आप में स्थानांतरित कर दिया है में (n/(2^n) == 0पूर्णांक विभाजन, n>1, और सकारात्मक साथ/अहस्ताक्षरित) परिणाम चाहिए: यहाँ सटीक कोड है कि मैं परीक्षण कर रहा हूँ है , लेकिन किसी भी तरह मेरा आउटपुट यहां है:

100000 
100000 
100000 

क्या मैं पागल हूं? संभवतः क्या हो सकता है?

+0

@ShafikYaghmour: यह संकलक मानता है एक निर्देश में डाल भी परेशान है। इस कार्यक्रम को अस्वीकार करने के अपने अधिकार में यह ठीक है। – MSalters

+0

@MSalters वास्तव में, हम इस बिंदु पर विशिष्ट संकलक/मंच/संस्करण में शामिल हो रहे हैं लेकिन वर्तमान और हाल के संस्करणों के लिए यह मामला है और जैसा कि मैंने पहले ही कहा है कि यह अनिर्धारित है, इसलिए आप स्पष्ट रूप से अपने आप हैं, 'gcc' केवल ऐसा लगता है '-O0' का उपयोग करते समय 'shr' का उत्पादन करें। –

+0

@ShafikYaghmour: इंटेल जीसीसी द्वारा समर्थित कई प्लेटफार्मों में से एक है, और उनके पास अलग-अलग अनुकूलन चरण हैं। ऑप्टिमाइज़ेशन में एक आम चाल यह कहना है कि "यह मान केवल 0 और 31 के बीच हो सकता है क्योंकि इसका उपयोग शिफ्ट में किया जाता है, अगर मैं कोड प्राप्त करने के लिए कोड पथ एक्स का पालन करता हूं तो मान 0 और 31 के बीच नहीं होगा, इसलिए कोड पथ एक्स असंभव है और मुझे इसके लिए निर्देश उत्पन्न करने की भी आवश्यकता नहीं है "। जीसीसी प्रसिद्ध रूप से शून्य सूचक जांच के लिए करता है। – MSalters

उत्तर

44

सी में सी ++ में, शिफ्ट स्थान के आकार (बिट्स में) तक सीमित हैं। उदाहरण के लिए, यदि हस्ताक्षरित int 32 बिट्स है, तो 31 से अधिक की एक शिफ्ट अपरिभाषित है।

प्रैक्टिस में, एक आम परिणाम यह है कि शिफ्ट राशि के 5 कम-महत्वपूर्ण महत्वपूर्ण बिट्स का उपयोग किया जाता है और उच्च ऑर्डर बिट्स को अनदेखा किया जाता है; यह एक मशीन निर्देश बनाने वाले कंपाइलर के कारण है जो वास्तव में करता है (उदाहरण के लिए x86 पर एसएचआर)।

इस मामले में, शिफ्ट मान 100000 (दशमलव) है जो 11000011010100000 बाइनरी में होता है - निचले 5 बिट शून्य होते हैं। तो, आप प्रभावी रूप से 0 से शिफ्ट प्राप्त कर रहे हैं। आपको इस पर भरोसा नहीं करना चाहिए; तकनीकी रूप से, आप जो देख रहे हैं वह अपरिभाषित व्यवहार है।

संदर्भ:

सी के लिए, N1570 खंड 6.5.7:

तो सही संकार्य के मूल्य नकारात्मक है या पदोन्नत बाईं संकार्य की चौड़ाई के बराबर या अधिक या है, व्यवहार अपरिभाषित है।

सी ++ के लिए, N3690 खंड 5.8 "[expr.shift]":

अगर सही संकार्य के टुकड़े में नकारात्मक, या अधिक से अधिक से या लंबाई के बराबर है व्यवहार अपरिभाषित है प्रचारित बाएं ऑपरेंड।

एन 1570 एक ड्राफ्ट है, जो लगभग जारी आईएसओ सी 11 मानक के समान है; 1 9 8 9 एएनएसआई सी मानक के बाद से यह खंड काफी समान रहा है।

N3690 सी ++ मानक का हालिया मसौदा है; मुझे यकीन नहीं है कि यह उपयोग करने के लिए सबसे अच्छा है, लेकिन फिर, यह खंड नहीं बदला है।

+1

क्या आपने इस व्यवहार को विभिन्न कंपाइलरों के साथ देखा है या कुछ जगहों से पढ़ा है? –

+3

@GrijeshChauhan, यह सी और सी ++ मानक विनिर्देशों में प्रलेखित है। एसएचआर निर्देश की पीढ़ी के संबंध में, मैंने यह देखा है। – davmac

+0

कोडिंग की पवित्र मां ... मैंने अभी इसका परीक्षण किया है और 100000 की बाइनरी '0b110000110101_00000' है। मैंने 100001 तक स्थानांतरित करने की कोशिश की, और वास्तव में इसे 1 – Suedocode

31

आप undefined behavior लागू कर रहे हैं यदि आप बाईं संकार्य के बिट लंबाई से अधिक बदलाव, draft C++ standard अनुभाग 5.8शिफ्ट ऑपरेटरों पैरा कहते हैं (जोर मेरा):

ऑपरेंड करेगा अभिन्न या unscoped गणना प्रकार और अभिन्न पदोन्नति का प्रदर्शन किया जाता है।परिणाम का प्रकार प्रचारित बाएं ऑपरेंड का है। व्यवहार सही है, यदि सही ऑपरेंड नकारात्मक है, या प्रचारित बाएं ऑपरेंड के बिट्स में लंबाई से अधिक या बराबर है।

दिलचस्प ध्यान दें कि दोनों gcc और clang इस कोड के लिए एक चेतावनी उत्पन्न हो सकता है अगर पारी राशि अगर एक शाब्दिक करने के लिए:,

cout << (b>> 100000) ; 

या यदि b एक स्थिरांक है gcc के लिए चेतावनी निम्नानुसार है:

warning: right shift count >= width of type [enabled by default] 

रूप MSalters प्रश्न के टिप्पणी में बताते हैं, हम भी नहीं इस चेतावनी पर भरोसा करने में सक्षम के बाद से इस अपरिभाषित व्यवहार, जो संगत है है के साथ मानकों मामले में अपरिभाषित व्यवहार पर ध्यान दें और हो सकता है परिभाषाएँ अनुभाग जो कहते हैं:

नोट: [...] अनुमत अपरिभाषित व्यवहार, अप्रत्याशित परिणामों के साथ पूरी तरह से स्थिति अनदेखी अनुवाद या पर्यावरण का एक दस्तावेज ढंग विशेषता में प्रोग्राम निष्पादन के दौरान व्यवहार कर करने से (के साथ पर्वतमाला या एक डायग्नोस्टिक संदेश जारी किए बिना), एक अनुवाद समाप्त करने के लिए टयन या निष्पादन (नैदानिक ​​संदेश जारी करने के साथ)। [...]

प्लेटफार्म विशिष्ट विवरण

उदाहरण कोड में बदलाव के स्पष्ट कमी के लिए एक संभावित व्याख्या हो सकता है क्योंकि कुछ प्लेटफार्मों पर पारी गिनती नकाबपोश5 bits होगा एक x86 वास्तुकला पर उदाहरण के लिए हम Intel® 64 and IA-32 Architectures Software Developer’s Manual अनुभाग देख सकते हैं साल/एसएआर/SHL/SHR-शिफ्ट IA-32 आर्किटेक्चर संगतता खंड में का कहना है:

0,123,

8086 शिफ्ट गणना को मुखौटा नहीं करता है। हालांकि, अन्य सभी आईए -32 प्रोसेसर (इंटेल 286 प्रोसेसर से शुरू होते हैं) शिफ्ट को 5 बिट्स पर मास्क करते हैं, जिसके परिणामस्वरूप 31 की अधिकतम गणना होती है। [...]

+0

80286 जानबूझकर शिफ्ट की मात्रा शब्द के आकार की अनुमति देता है, समावेशी। मुझे आश्चर्य है कि क्यों 80386 ने ऐसा नहीं किया था (ऑपरेटर आकार 32 बिट्स के दौरान सीएल के 6 बिट्स का उपयोग करके)? – supercat

+0

x86 पर अधिक पृष्ठभूमि के लिए [यह ब्लॉग पोस्ट] (https://david.wragg.org/blog/2012/11/shift-instructions.html) भी देखें। –

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