কেন 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
এই প্রোগ্রামটিতে আরো আকর্ষণীয় জিনিস যে এটা সত্য হয় শুধুমাত্র জন্য -0x80000000, কিন্তু জন্য মিথ্যা -0x80000000L,-2147483648 এবং -2147483648Lকেন int- এ আক্ষরিক হল: (জিসিসি 4.1.2), তাই প্রশ্ন হল -0x80000000int- এ আক্ষরিক থেকে আলাদা -2147483648?
Andreas Fester

2
@ বাথশেবা আমি সবেমাত্র অনলাইন সংকলক টিউটোরিয়ালসপয়েন্ট.কমডিংগ্রাউন্ড
জয়েশ ভোই

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। এছাড়াও এল প্রত্যয় বলছেন যে আপনি একটি চান long যদি সম্ভব । Suff.৪.৪.১-তে উল্লিখিত টেবিলটি পড়া চালিয়ে যাওয়া অবলম্বন করলে এল প্রত্যয়টির আসলে একইরকম বিধি রয়েছে: যদি অনুরোধের ভিতরে নম্বরটি ফিট না হয় long, যা এটি 32 বিটের ক্ষেত্রে হয় না, সংকলক আপনাকে long longযেখানে এটি দেবে ঠিক ঠিক মাপসই করা হবে।


3
"... আক্ষরিক -2147483648L এর সাথে প্রতিস্থাপন করুন আপনি স্পষ্টতই একটি দীর্ঘ পান যা স্বাক্ষরিত হয়।" হুম, একটি 32 বিট ইন longসিস্টেম 2147483648L, একটি মাপসই করা হবে না long, তাই এটি হয়ে long long, তারপর- প্রয়োগ করা হয় - বা তাই আমি চিন্তা।
chux - মনিকা পুনরায় ইনস্টল করুন

2
@ এএএসএচ, কারণ কোনও ইনট হতে পারে সর্বাধিক সংখ্যা 0x7FFFFFFF। এটি নিজে চেষ্টা করুন:#include <limits.h> printf("%X\n", INT_MAX);
লন্ডিন

5
@ এএএসএচ একটি স্বাক্ষরযুক্ত সংখ্যার অন্তর্নিহিত বাইনারি উপস্থাপনার সাথে উত্স কোডে পূর্ণসংখ্যার লিটারালগুলির হেক্সাডেসিমাল উপস্থাপনাটিকে বিভ্রান্ত করবেন না। 0x7FFFFFFFসোর্স কোডে যখন লেখা থাকে তখন আক্ষরিক সবসময় একটি ধনাত্মক সংখ্যা থাকে তবে আপনার intপরিবর্তনশীলটিতে অবশ্যই 0xFFFFFFFF এর মান পর্যন্ত কাঁচা বাইনারি সংখ্যা থাকতে পারে।
লন্ডিন

2
@ এএসএইচ ìnt n = 0x80000000স্বাক্ষরযুক্ত আক্ষরিক থেকে একটি স্বাক্ষরিত ধরণের রূপান্তর করতে বাধ্য করে। যা ঘটবে তা আপনার সংকলক পর্যন্ত - এটি বাস্তবায়ন-সংজ্ঞায়িত আচরণ। intসাইন বিটকে ওভাররাইট করে এই ক্ষেত্রে এটি পুরো আক্ষরিক দেখানোতে বেছে নিয়েছে । অন্যান্য সিস্টেমে এটি প্রকারের প্রতিনিধিত্ব করা সম্ভব নাও হতে পারে এবং আপনি অনির্ধারিত আচরণের আবেদন করেন - প্রোগ্রামটি ক্র্যাশ হতে পারে। আপনি যদি int n=2147483648;এটি করেন তবে এটি হেক্স নোটেশনের সাথে মোটেই সম্পর্কিত নয় তবে আপনিও একই আচরণ পাবেন ।
লন্ডিন

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এটিতে 2 এস প্রশংসা গণিত গ্রহণ করি এবং করি তবে আমরা এটি পাই:

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

তাই -0x80000000 == 0x80000000। এবং তুলনা (0 < 0x80000000)(যেহেতু 0x80000000স্বাক্ষরবিহীন) সত্য।


এটি ধরে রাখে 32-বিট intএস। যদিও এটি খুব সাধারণ পছন্দ, যে কোনও প্রদত্ত বাস্তবায়ন intহ'ল সংক্ষিপ্ততর বা বিস্তৃত হতে পারে। তবে, এই ক্ষেত্রে এটি একটি সঠিক বিশ্লেষণ।
জন বলিঞ্জার

এটি ওপির কোডের সাথে প্রাসঙ্গিক নয়, -0x80000000স্বাক্ষরবিহীন পাটিগণিত। ~0x800000000বিভিন্ন কোড।
এমএম

এটি আমার কাছে সহজভাবে দেওয়া সেরা এবং সঠিক উত্তর বলে মনে হচ্ছে। @ এমএম তিনি কীভাবে দ্বিগুণ পরিপূরক গ্রহণ করবেন তা ব্যাখ্যা করছেন। এই উত্তরটি নির্দিষ্ট করে addressesণাত্মক চিহ্নটি সংখ্যায় কী করছে।
অক্টোপাস

@ অ্যাক্টপাস নেতিবাচক চিহ্নটি সংখ্যার (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এবং unsigned48-বিট আছে।

তারপর 0x80000000ফিট করে intএবং তাই টাইপ int-0x80000000তারপরে একটি নেতিবাচক সংখ্যা এবং প্রিন্ট আউটের ফলাফলটি আলাদা।

[আসল কথায় ফিরে]

যেহেতু 0x80000000কোনও স্বাক্ষরিত টাইপের আগে কিছু স্বাক্ষরিত টাইপের সাথে এটি ফিট হয় কারণ এটি এর some_signed_MAXমধ্যে এখনও বেশ বড় some_unsigned_MAX, এটি কিছু স্বাক্ষরবিহীন প্রকার।


8

সি একটি নিয়ম যে পূর্ণসংখ্যা আক্ষরিক হতে পারে হয়েছে signedবা unsignedতা মধ্যে ফিট করে উপর নির্ভর করে signedবা unsigned(পূর্ণসংখ্যা প্রচার)। একটি 32বিট মেশিনে আক্ষরিক 0x80000000হবে unsigned। 2 এর সম্পূরক -0x80000000হয় 0x80000000 একটি 32 বিট মেশিনে। অতএব, তুলনা bal < INT32_MINমধ্যে signedএবং unsignedএবং C নিয়ম অনুযায়ী তুলনা সামনে unsigned intরূপান্তরিত হবেlong long

সি 11: 6.3.1.8/1:

[...] অন্যথায়, যদি স্বাক্ষরিত পূর্ণসংখ্যার ধরণের অপারেন্ডের ধরণটি স্বাক্ষরযুক্ত পূর্ণসংখ্যার প্রকারের সাথে অপারেন্ডের ধরণের সমস্ত মানকে উপস্থাপন করতে পারে তবে স্বাক্ষরযুক্ত পূর্ণসংখ্যার ধরণের অপারেন্ডটি অপারেন্ডের ধরণের সাথে রূপান্তরিত হয় স্বাক্ষরিত পূর্ণসংখ্যার প্রকার।

অতএব, bal < INT32_MINসর্বদা হয় true

আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.