عملية المقارنة على أعداد صحيحة غير موقعة وموقعة

StackOverflow https://stackoverflow.com/questions/2084949

  •  21-09-2019
  •  | 
  •  

سؤال

انظر مقتطف الرمز هذا

int main()
{ 
 unsigned int a = 1000;
 int b = -1;
 if (a>b) printf("A is BIG! %d\n", a-b);
 else printf("a is SMALL! %d\n", a-b); 
 return 0;
}   

هذا يعطي الإخراج: A صغير: 1001

لا أفهم ما يحدث هنا. كيف يعمل المشغل هنا؟ لماذا "أصغر من" ب "؟ إذا كان الأمر أصغر بالفعل ، فلماذا أحصل على رقم إيجابي (1001) كفرق؟

هل كانت مفيدة؟

المحلول

يتم تنفيذ العمليات الثنائية بين الأنواع المتكاملة المختلفة ضمن نوع "مشترك" محدد من قبل ما يسمى تحويلات الحساب المعتادة (انظر مواصفات اللغة ، 6.3.1.8). في حالتك ، يكون النوع "المشترك" unsigned int. هذا يعني ذاك int المعامل (الخاص بك b) سيتم تحويلها إلى unsigned int قبل المقارنة ، وكذلك لغرض إجراء الطرح.

متي -1 يتم تحويله إلى unsigned int والنتيجة هي الحد الأقصى الممكن unsigned int القيمة (مثل UINT_MAX). وغني عن القول ، سيكون أكبر من غير موقعة 1000 القيمة ، وهذا يعني ذلك a > b هو في الواقع خطأ و a هو في الواقع صغير مقارنة ب (unsigned) b. ال if في الكود الخاص بك يجب حل إلى else الفرع ، وهو ما لاحظته في تجربتك.

تنطبق قواعد التحويل نفسها على الطرح. لك a-b يتم تفسيره حقًا على أنه a - (unsigned) b والنتيجة لها نوع unsigned int. لا يمكن طباعة هذه القيمة مع %d تنسيق محدد ، منذ ذلك الحين %d يعمل فقط مع وقعت القيم. محاولتك لطباعته مع %d النتائج في سلوك غير محدد ، وبالتالي فإن القيمة التي تراها مطبوعة (على الرغم من أن لديها تفسيرًا حتميًا منطقيًا في الممارسة) لا معنى لها تمامًا من وجهة نظر لغة C.

يحرر: في الواقع ، قد أكون مخطئًا في جزء السلوك غير المحدد. وفقًا لمواصفات لغة C ، يجب أن يكون للجزء المشترك من نطاق نوع عدد صحيح موقّع وغير موقّع تمثيلًا متطابقًا (مما يعني ، وفقًا للحاشية 31 ، "قابلية التبادل كوسيط للوظائف"). لذلك ، نتيجة a - b التعبير غير موقّع 1001 كما هو موضح أعلاه ، وما لم أفتقد شيئًا ما ، فمن القانوني طباعة هذه القيمة غير الموقعة المحددة مع %d المحدد ، لأنه يقع ضمن النطاق الإيجابي من int. الطباعة (unsigned) INT_MAX + 1 مع %d سيكون غير محدد ، ولكن 1001u على ما يرام.

نصائح أخرى

على التنفيذ النموذجي حيث int هو 32 بت ، -1 عند تحويله إلى unsigned int هو 4،294،967،295 وهو بالفعل 1000.

حتى لو تعاملت مع الطرح في unsigned العالمية، 1000 - (4,294,967,295) = -4,294,966,295 = 1,001 وهو ما تحصل عليه.

لهذا gcc سوف يبصقون تحذيرًا عند المقارنة unsigned مع signed. (إذا لم ترى تحذيرًا ، فالتعمر -Wsign-compare علَم.)

أنت تقوم بالمقارنة غير الموقعة ، أي مقارنة 1000 إلى 2^32 - 1.

يتم توقيع الإخراج بسبب ٪ d في printf.

NB أحيانًا يكون السلوك عند خلط المعاملات الموقعة وغير الموقعة محددة للمترجم. أعتقد أنه من الأفضل تجنبهم والقيام بالقوالب عندما تكون في شك.

ابحث عن طريقة سهلة للمقارنة ، وربما تكون مفيدة عندما لا تتمكن من التخلص من الإعلان غير الموقّع ، (على سبيل المثال ، [NSArray Count]) ، فقط أجبر "int غير الموقعة" إلى "int".

يرجى تصحيح لي إذا كنت مخطئا.

if (((int)a)>b) {
    ....
}

تم تصميم الجهاز لمقارنة التوقيع على التوقيع وغير موقعة إلى غير موقعة.

إذا كنت تريد النتيجة الحسابية ، قم بتحويل القيمة غير الموقعة إلى نوع أكبر موقّع أولاً. وإلا فإن المترجم يفترض أن المقارنة هي حقًا بين القيم غير الموقعة.

ويمثل -1 كـ 1111..1111 ، لذا فهي كمية كبيرة جدًا ... الأكبر ... عند تفسيرها على أنها غير موقعة.

 #include<stdio.h>
 int main()
 {
   int a = 1000;
   signed int b = -1, c = -2;
   printf("%d",(unsigned int)b);
   printf("%d\n",(unsigned int)c);
   printf("%d\n",(unsigned int)a);

   if(1000>-1){
      printf("\ntrue");
   }
   else 
     printf("\nfalse");
     return 0;
 }

لهذا عليك أن تفهم أسبقية المشغلين

  1. يعمل المشغلون العلائقيون من اليسار إلى اليمين ... لذلك عندما يأتي

    إذا (1000> -1)

ثم أولاً وقبل كل شيء ، سيتم تغييرها -1 إلى عدد صحيح غير موقّع لأن INT يتم معاملته افتراضيًا كرقم غير موقّع ويتراوحه أكبر من الرقم الموقّع

-1 سيتحول إلى الرقم غير الموقّع ، ويتحول إلى رقم كبير جدًا

أثناء مقارنة A> B حيث يكون A غير موقّع و B و B هو نوع int ، B هو النوع المصبوب إلى int غير موقعة لذلك ، يتم تحويل قيمة int الموقعة -1 إلى قيمة أقصى من غير موقعة ** (النطاق: 0 إلى (2^32) -1) ** وبالتالي ، يصبح> b ie ، (1000> 4294967296) خطأ. وبالتالي حلقة أخرى printf ("A صغير! ٪ d n" ، ab) ؛ أعدم.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top