2011-12-07 7 views
12

मुझे पता है, एक नकारात्मक हस्ताक्षरित प्रकार को सही ढंग से स्थानांतरित करना कार्यान्वयन पर निर्भर करता है, लेकिन यदि मैं बाएं शिफ्ट करता हूं तो क्या होगा? उदाहरण के लिए:क्या नकारात्मक पूर्णांक परिभाषित व्यवहार को बाएं और दाएं स्थानांतरित कर रहे हैं?

int i = -1; 
i << 1; 

क्या यह अच्छी तरह परिभाषित है?

मुझे लगता है कि मानक पर हस्ताक्षर किए प्रकार के साथ नकारात्मक मूल्य के बारे में नहीं कहा गया है

अगर E1 है एक हस्ताक्षरित प्रकार और गैर-नकारात्मक मान, और ई 1 × 2 E2 परिणाम प्रकार में प्रदर्शनीय है , तो वह परिणामस्वरूप मूल्य है; अन्यथा, व्यवहार अपरिभाषित है।

यह केवल स्पष्ट करता है कि यदि परिणाम हस्ताक्षरित प्रकार में प्रतिनिधित्व योग्य नहीं है तो व्यवहार अपरिभाषित है।

+8

कौन सा हिस्सा स्पष्ट नहीं है? * यदि * ई 1 का गैर-ऋणात्मक मान है और ... * अन्यथा * व्यवहार अपरिभाषित है। ई 1 का ऋणात्मक मूल्य है, इसलिए व्यवहार अपरिभाषित है। यह सच है कि कभी-कभी मानक कुछ अतिरिक्त ब्रैकेट के साथ ऐसा कर सकता है ताकि यह पूरी तरह स्पष्ट हो सके कि "अन्यथा" क्या संदर्भित करता है, लेकिन यहां इसका अर्थ है "किसी भी स्थिति में पहले से वर्णित नहीं है"। यह इन चीजों को याद रखने में मदद करता है कि * किसी * स्थिति में जहां मानक व्यवहार का वर्णन नहीं करता है, तो व्यवहार अपरिभाषित होता है। तो वास्तव में "अन्यथा" औपचारिक रूप से अनावश्यक है। –

+0

@SteveJessop: मुझे लगता है कि __otherwise__ का अर्थ है कि यदि मूल्य प्रतिनिधित्व योग्य नहीं है तो व्यवहार अपरिभाषित है। मुझे यकीन नहीं है कि इसमें नकारात्मक मूल्य के साथ ई 1 शामिल है। – user103214

+1

@ नॉर्मन: ऐसा लगता है, आर। मार्थिन्हो का जवाब देखें, एक अर्धविराम है, स्थिति और अंतिम परिणाम के बीच एक स्पष्ट सेपरेटर है। – Xeo

उत्तर

24

आप उस वाक्य को सही ढंग से नहीं पढ़ रहे हैं। मानक इसे परिभाषित करता है यदि: बाएं ऑपरेंड पर हस्ताक्षर किए गए प्रकार और एक गैर-ऋणात्मक मान और परिणाम दर्शाए जा सकते हैं (और पहले उसी अनुच्छेद में इसे हस्ताक्षरित प्रकारों के लिए परिभाषित किया गया है)। अन्य सभी मामलों में (उस वाक्य में use of the semicolon पर ध्यान दें), यानी, यदि इनमें से कोई भी स्थिति सत्यापित नहीं है, तो व्यवहार अपरिभाषित है।

+1

+1। अर्धविराम – Xeo

+1

+1 क्या होगा यदि मेरे पास गैर-नकारात्मक था और मैं इसे कई बार सही स्थानांतरित करता हूं? 'int i = 1; i >> 24; 'क्या यह मान्य है? बस उलझन में – Pubby

+0

के लिए – user103214

3

अन्यथा, व्यवहार अपरिभाषित है।

यह

शामिल करता है, तो ई 1 एक हस्ताक्षरित प्रकार और गैर-नकारात्मक मान

11

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

सी मानक के लेखक यह नहीं कहना चाहते थे कि उन मशीनों के लिए कंपाइलर्स जहां नकारात्मक संख्याओं के बाएं स्थानांतरित हो जाएंगे, ऐसे फंसे को रोकने के लिए संशोधित किया जाना चाहिए (क्योंकि प्रोग्राम संभावित रूप से इस पर भरोसा कर सकते हैं), लेकिन अगर बाएं- एक ऋणात्मक संख्या को स्थानांतरित करने के लिए एक जाल को ट्रिगर करने की अनुमति दी जाती है जो किसी भी मनमाना व्यवहार (यादृच्छिक कोड निष्पादन सहित) का कारण बन सकती है जिसका अर्थ है कि ऋणात्मक संख्या को छोड़कर किसी भी चीज़ को करने की अनुमति है। इसलिए अपरिभाषित व्यवहार।

व्यवहार में, के बारे में 5 साल पहले तक, compilers के 99 +% एक मशीन (जिसका अर्थ है 1990 के बाद से बनाया मशीनों के 99 +%) लगातार x<<y और x>>y के लिए निम्नलिखित व्यवहार उपज होता है कि two's-पूरक गणित का इस्तेमाल किया के लिए लिखा है, इस हद तक कि इस तरह के व्यवहार पर कोड निर्भरता को कोड से अधिक गैर-पोर्टेबल माना जाता था, जिसे char माना गया था 8 बिट्स। सी मानक ने इस तरह के व्यवहार को अनिवार्य नहीं किया था, लेकिन किसी भी कंपाइलर लेखक मौजूदा कोड के विस्तृत आधार के साथ संगत होना चाहते हैं, इसका पालन करेंगे।

  • अगर y एक हस्ताक्षरित प्रकार है, x << y और x >> y मूल्यांकन किया जाता है जैसे कि y अहस्ताक्षरित के लिए चुना गया।
  • यदि x टाइप int है, x<<y(int)((unsigned)x << y) के बराबर है।
  • यदि xint टाइप करें और सकारात्मक, x>>y(unsigned)x >> y के बराबर है। यदि xint प्रकार और नकारात्मक है, x>>y `~ (~ ((हस्ताक्षरित) x) >> y के बराबर है)।
  • यदि xlong प्रकार है, तो समान नियम लागू होते हैं, लेकिन के साथ unsigned के बजाय।
  • अगर x एक एन-बिट प्रकार है और y एन 1 से अधिक है, तो x >> y और x << y मनमाने ढंग से शून्य उपज सकता है, या के रूप में यद्यपि दायां संकार्य y % N था में कार्य कर सकते है; उन्हें y पर आनुपातिक अतिरिक्त समय की आवश्यकता हो सकती है [ध्यान दें कि 32-बिट मशीन पर, यदि y ऋणात्मक है, तो संभावित रूप से लंबा समय हो सकता है, हालांकि मुझे केवल एक मशीन की जानकारी है जो अभ्यास में 256 से अधिक अतिरिक्त कदम चलाएगा ]। कंपाइलर्स अपनी पसंद में जरूरी नहीं थे, लेकिन हमेशा संकेतों में से किसी एक को अन्य दुष्प्रभावों के साथ वापस नहीं करेंगे।

दुर्भाग्य से किसी कारण मैं काफी नहीं जान सकता के लिए, संकलक लेखकों का फैसला किया है कि बजाय इंगित करने के लिए क्या मान्यताओं compilers मृत-कोड को हटाने के लिए उपयोग करना चाहिए प्रोग्रामर देने से, compilers मान लेना चाहिए कि यह किसी भी बदलाव पर अमल करना असंभव है जिसका व्यवहार सी मानक द्वारा अनिवार्य नहीं है। की तरह इस प्रकार, दिया कोड निम्नलिखित:

uint32_t shiftleft(uint32_t v, uint8_t n) 
{ 
    if (n >= 32) 
    v=0; 
    return v<<n; 
} 

एक संकलक कि निर्धारित कर सकते हैं क्योंकि कोड अपरिभाषित व्यवहार में संलग्न हैं जब n 32 या बड़ा है, संकलक मान सकते हैं कि if वापस कभी नहीं होगा सच है, और इस तरह हो सकता है कोड छोड़ो। नतीजतन, जब तक कि कोई व्यक्ति सी के लिए मानक के साथ आता है, जो क्लासिक व्यवहार को पुनर्स्थापित करता है और प्रोग्रामर को यह निर्धारित करने की अनुमति देता है कि कौन सी धारणा मृत कोड हटाने की योग्यता है, ऐसे किसी भी कोड के लिए ऐसी संरचनाओं की सिफारिश नहीं की जा सकती है जो एक हाइपर-आधुनिक कंपाइलर को खिलाया जा सकता है।

+1

इस अद्भुत उत्तर के लिए धन्यवाद - भले ही यह स्वीकार नहीं किया गया हो, यह बहुत उपयोगी है। –

+0

ध्यान रखने योग्य एक और बात यह है कि सभी बैरल-शिफ्टर्स समान नहीं हैं। मुझे लगता है कि एआरएम आईए 32 और अन्य प्लेटफॉर्म की तुलना में थोड़ा अलग व्यवहार करता है, और इसका कारण शिफ्ट राशि के केवल निम्न बिट्स का उपयोग करके एक अंतर्निहित मॉड ऑपरेशन नहीं है। – jww

+0

@jww: प्लेटफार्म जिनमें "शिफ्ट-बाय-एन" निर्देश शामिल होता है, अक्सर शिफ्ट मूल्य को कम करता है, लेकिन कई मामलों में मॉड-कमी शब्द आकार से बड़ी राशि से होती है। इसके अलावा, परिवार में अलग-अलग चिप्स अलग-अलग व्यवहार कर सकते हैं। हालांकि, लगभग सभी प्रोसेसर सूचीबद्ध दो व्यवहारों में से एक का उपयोग करेंगे। – supercat

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