0 <-0x80000000 क्यों है?


253

मेरे पास एक सरल कार्यक्रम है:

#include <stdio.h>

#define INT32_MIN        (-0x80000000)

int main(void) 
{
    long long bal = 0;

    if(bal < INT32_MIN )
    {
        printf("Failed!!!");
    }
    else
    {
        printf("Success!!!");
    }
    return 0;
}

शर्त if(bal < INT32_MIN )हमेशा सच होती है। यह कैसे संभव है?

अगर मैं मैक्रो को निम्न में बदलूं तो यह ठीक काम करता है:

#define INT32_MIN        (-2147483648L)

क्या कोई इस मुद्दे को इंगित कर सकता है?


3
कितना है CHAR_BIT * sizeof(int)?
5gon12eder

1
क्या आपने बेल आउट प्रिंट करने की कोशिश की है?
रयान फिट्जपैट्रिक

10
IMHO अधिक दिलचस्प बात यह है कि यह केवल के लिए सच है -0x80000000, लेकिन गलत है -0x80000000L, -2147483648और -2147483648L(gcc 4.1.2), इसलिए सवाल यह है कि इंट शाब्दिक -0x80000000अंतर शाब्दिक से अलग क्यों है -2147483648?
एंड्रियास फस्टर

2
@ बाथशीबा मैं सिर्फ ऑनलाइन कंपाइलर tutorialspoint.com/codingground.htm
Jayesh Bhoi

2
यदि आपने कभी देखा है कि (के कुछ अवतार) के रूप में <limits.h>परिभाषित INT_MINकरता है (-2147483647 - 1), तो अब आप जानते हैं कि क्यों।
zwol

जवाबों:


363

यह काफी सूक्ष्म है।

आपके प्रोग्राम में प्रत्येक पूर्णांक शाब्दिक प्रकार है। किस प्रकार का यह 6.4.4.1 में एक तालिका द्वारा विनियमित है:

Suffix      Decimal Constant    Octal or Hexadecimal Constant

none        int                 int
            long int            unsigned int
            long long int       long int
                                unsigned long int
                                long long int
                                unsigned long long int

यदि एक शाब्दिक संख्या डिफ़ॉल्ट intप्रकार के अंदर फिट नहीं हो सकती है , तो यह अगले बड़े प्रकार का प्रयास करेगा जैसा कि उपरोक्त तालिका में दर्शाया गया है। तो नियमित दशमलव पूर्णांक शाब्दिक के लिए यह इस प्रकार है:

  • प्रयत्न int
  • अगर यह फिट नहीं हो सकता है, तो कोशिश करें long
  • अगर यह फिट नहीं हो सकता है, तो कोशिश करें long long

हेक्स शाब्दिक हालांकि अलग तरह से व्यवहार करते हैं! यदि शाब्दिक हस्ताक्षरित प्रकार के अंदर फिट नहीं हो सकता है int, तो यह unsigned intबड़े प्रकारों की कोशिश करने से पहले पहले प्रयास करेगा । उपरोक्त तालिका में अंतर देखें।

तो 32 बिट सिस्टम पर, आपका शाब्दिक 0x80000000प्रकार है unsigned int

इसका मतलब यह है कि आप -कार्यान्वयन-परिभाषित व्यवहार को लागू किए बिना एकतरफा ऑपरेटर को शाब्दिक रूप से लागू कर सकते हैं, जैसा कि आप अन्यथा हस्ताक्षरित पूर्णांक को ओवरफ्लो करते समय करते हैं। इसके बजाय, आपको मूल्य मिलेगा 0x80000000, एक सकारात्मक मूल्य।

bal < INT32_MINसामान्य अंकगणितीय रूपांतरणों को आमंत्रित करता है और अभिव्यक्ति के परिणाम 0x80000000को बढ़ावा दिया जाता unsigned intहै long long। मान 0x80000000संरक्षित है और 0, 0x80000000 से कम है, इसलिए परिणाम।

जब आप 2147483648Lदशमलव को अपने साथ दशमलव संकेतन का उपयोग करते हैं और इसलिए संकलक नहीं चुनता है unsigned int, बल्कि इसे एक के अंदर फिट करने की कोशिश करता है long। इसके अलावा L प्रत्यय कहता है कि आप long यदि संभव हो तो चाहते हैं । L प्रत्यय वास्तव में इसी तरह के नियम हैं यदि आप उल्लिखित तालिका को 6.4.4.1 में पढ़ना जारी रखते हैं: यदि संख्या अनुरोध के अंदर फिट नहीं होती है long, जो कि 32 बिट मामले में नहीं होती है, तो संकलक आपको एक long longजगह देगा। ठीक रहेगा।


3
"" शाब्दिक बदलें -2147483648L के साथ आप स्पष्ट रूप से एक लंबा हो जाता है, जिस पर हस्ताक्षर किए जाते हैं। " हममम, एक 32-बिट में longप्रणाली 2147483648L, एक में फिट नहीं हो long, तो यह हो जाता है long long, तो- लागू किया जाता है - या तो मैंने सोचा।
chux - मोनिका

2
@ क्योंकि अधिकतम संख्या एक int हो सकती है 0x7FFFFFFF। इसे स्वयं आजमाएँ:#include <limits.h> printf("%X\n", INT_MAX);
लंडिन

5
@ साइन कोड के अंतर्निहित बाइनरी प्रतिनिधित्व के साथ स्रोत कोड में पूर्णांक शाब्दिक प्रतिनिधित्व के हेक्साडेसिमल को भ्रमित न करें। 0x7FFFFFFFजब स्रोत कोड में लिखा गया शाब्दिक हमेशा एक सकारात्मक संख्या होती है, लेकिन आपके intचर में निश्चित रूप से 0xFFFFFFFF मान तक कच्चे बाइनरी नंबर हो सकते हैं।
लंडिन

2
@ डैश ìnt n = 0x80000000अहस्ताक्षरित शाब्दिक से हस्ताक्षरित प्रकार पर रूपांतरण करता है। आपके कंपाइलर पर क्या होगा - यह कार्यान्वयन-परिभाषित व्यवहार है। इस मामले में इसने intसाइन बिट को ओवरराइट करते हुए पूरे शाब्दिक को दिखाना चुना । अन्य प्रणालियों पर इस प्रकार का प्रतिनिधित्व करना संभव नहीं हो सकता है और आप अपरिभाषित व्यवहार को लागू कर सकते हैं - कार्यक्रम दुर्घटनाग्रस्त हो सकता है। यदि आप ऐसा करते हैं int n=2147483648;तो आपको बहुत ही व्यवहार मिलेगा, यह हेक्स नोटेशन से संबंधित नहीं है।
लंडिन 16

3
-अहस्ताक्षरित पूर्णांकों के लिए कैसे लागू किया जाता है इसका स्पष्टीकरण थोड़ा विस्तारित किया जा सकता है। मैंने हमेशा यह मान लिया था (हालांकि सौभाग्य से इस धारणा पर कभी भरोसा नहीं किया गया) कि अहस्ताक्षरित मूल्यों पर हस्ताक्षर किए गए मूल्यों के लिए "पदोन्नत" किया जाएगा, या संभवतः यह परिणाम अपरिभाषित होगा। (ईमानदारी से, यह एक संकलन-त्रुटि होना चाहिए; - 3uइसका क्या मतलब है?)
काइल स्ट्रैंड

27

0x80000000unsigned2147483648 मूल्य के साथ एक शाब्दिक है।

इस पर अनार्य माइनस लागू करना अभी भी आपको एक गैर-शून्य मान के साथ एक अहस्ताक्षरित प्रकार देता है। (वास्तव में, एक गैर-शून्य मान के लिए x, आपके द्वारा समाप्त मूल्य है UINT_MAX - x + 1।)


23

इस पूर्णांक शाब्दिक 0x80000000प्रकार है unsigned int

सी स्टैंडर्ड के अनुसार (6.4.4.1 पूर्णांक स्थिरांक)

5 पूर्णांक स्थिरांक का प्रकार संबंधित सूची में पहला है जिसमें इसके मूल्य का प्रतिनिधित्व किया जा सकता है।

और इस पूर्णांक स्थिरांक के प्रकार द्वारा प्रतिनिधित्व किया जा सकता है unsigned int

तो यह अभिव्यक्ति

-0x80000000एक ही unsigned intप्रकार है। इसके अलावा यह 0x80000000दो के पूरक प्रतिनिधित्व में समान मूल्य है जो निम्न तरीके से गणना करता है

-0x80000000 = ~0x80000000 + 1 => 0x7FFFFFFF + 1 => 0x80000000

उदाहरण के लिए लिखने पर इसका साइड इफेक्ट होता है

int x = INT_MIN;
x = abs( x );

परिणाम फिर से होगा INT_MIN

इस प्रकार इस हालत में

bal < INT32_MIN

सामान्य अंकगणितीय रूपांतरणों के नियमों के अनुसार लंबे समय तक इंट में परिवर्तित किए गए अहस्ताक्षरित मान के 0साथ तुलना की जाती है ।0x80000000

यह स्पष्ट है कि 0 से कम है 0x80000000


12

संख्यात्मक स्थिरांक 0x80000000प्रकार है unsigned int। अगर हम -0x80000000इस पर 2s तारीफ गणित लेते हैं और करते हैं, तो हमें यह मिलता है:

~0x80000000 = 0x7FFFFFFF
0x7FFFFFFF + 1 = 0x80000000

तो -0x80000000 == 0x80000000। और तुलना (0 < 0x80000000)(चूंकि 0x80000000अहस्ताक्षरित है) सच है।


यह 32-बिट intएस को दबाता है । हालांकि यह बहुत ही सामान्य विकल्प है, किसी भी कार्यान्वयन में intसंकीर्ण या व्यापक हो सकता है। हालाँकि यह उस मामले के लिए एक सही विश्लेषण है।
जॉन बोलिंगर ने 15

यह ओपी के कोड के लिए प्रासंगिक नहीं है, -0x80000000अहस्ताक्षरित अंकगणित है। ~0x800000000अलग कोड है।
एमएम

यह मेरे लिए सबसे अच्छा और सही जवाब लगता है बस डाल दिया। @MM वह बता रहा है कि कैसे एक टोमस पूरक लेना है। यह उत्तर विशेष रूप से पता करता है कि संख्या के लिए नकारात्मक संकेत क्या कर रहा है।
ऑक्टोपस 20

@ ऑक्टोपस ऋणात्मक चिह्न संख्या के लिए 2 के पूरक को लागू नहीं कर रहा है (!) हालांकि यह स्पष्ट लगता है, यह वर्णन नहीं कर रहा है कि कोड में क्या होता है -0x80000000! वास्तव में 2 का पूरक इस सवाल से पूरी तरह अप्रासंगिक है।
एमएम

12

यह सोचने का भ्रम होता है -कि संख्यात्मक स्थिरांक का हिस्सा क्या है।

नीचे दिए गए कोड 0x80000000में संख्यात्मक स्थिर है। इसका प्रकार केवल उसी पर निर्धारित होता है। -बाद में लागू किया जाता है और प्रकार में परिवर्तन नहीं होता

#define INT32_MIN        (-0x80000000)
long long bal = 0;
if (bal < INT32_MIN )

कच्चे अविकसित संख्यात्मक स्थिरांक धनात्मक होते हैं।

यदि यह दशमलव है, तो प्रकार सौंपा पहले प्रकार है कि यह आयोजन करेगा है: int, long, long long

यदि लगातार अष्टाधारी या हेक्साडेसिमल है, यह पहले प्रकार हैं कि उनके पास हो जाता है: int, unsigned, long, unsigned long, long long,unsigned long long

0x80000000, ओपी की प्रणाली पर unsignedया के प्रकार हो जाता है unsigned long। किसी भी तरह से, यह कुछ अहस्ताक्षरित प्रकार है।

-0x80000000कुछ गैर-शून्य मान भी है और कुछ अहस्ताक्षरित प्रकार के होने के कारण, यह 0. से अधिक है। जब कोड तुलना करता है कि ए long long, मूल्यों की तुलना के 2 किनारों पर नहीं बदला 0 < INT32_MINजाता है , तो यह सच है।


एक वैकल्पिक परिभाषा इस जिज्ञासु व्यवहार से बचती है

#define INT32_MIN        (-2147483647 - 1)

आइए हम कुछ समय के लिए काल्पनिक भूमि में चलते हैं जहां intऔरunsigned हैं 48-बिट हैं।

फिर में 0x80000000फिट बैठता है intऔर इसलिए प्रकार है int-0x80000000तब एक ऋणात्मक संख्या होती है और प्रिंट आउट का परिणाम भिन्न होता है।

[वास्तविक शब्द पर वापस जाएं]

चूंकि 0x80000000हस्ताक्षरित प्रकार से पहले कुछ अहस्ताक्षरित प्रकार में फिट बैठता है क्योंकि यह some_signed_MAXअभी तक की तुलना में बड़ा है some_unsigned_MAX, यह कुछ अहस्ताक्षरित प्रकार है।


8

C का नियम है कि पूर्णांक शाब्दिक हो सकता है signedया unsignedइस पर निर्भर करता है कि यह (पूर्णांक पदोन्नति) में फिट बैठता है signedया नहीं unsigned। एक इन 32-बिट मशीन पर शाब्दिक 0x80000000होगा unsigned। के 2 के पूरक -0x80000000है 0x80000000 एक 32-बिट मशीन पर। इसलिए, तुलना bal < INT32_MINबीच में है signedऔर unsignedसी नियम के अनुसार तुलना करने से पहले की unsigned intजाएगी long long

C11: 6.3.1.8/1:

[...] अन्यथा, यदि हस्ताक्षरित पूर्णांक प्रकार के साथ ऑपरेंड का प्रकार सभी प्रकार के मानों को निरूपित पूर्णांक प्रकार के साथ प्रदर्शित कर सकता है, तो अहस्ताक्षरित पूर्णांक प्रकार वाला ऑपरेटर के प्रकार के साथ परिवर्तित हो जाता है हस्ताक्षरित पूर्णांक प्रकार।

इसलिए, bal < INT32_MINहमेशा है true

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.