عملية المقارنة على أعداد صحيحة غير موقعة وموقعة
سؤال
انظر مقتطف الرمز هذا
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;
}
لهذا عليك أن تفهم أسبقية المشغلين
يعمل المشغلون العلائقيون من اليسار إلى اليمين ... لذلك عندما يأتي
إذا (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) ؛ أعدم.