سؤال

unsigned char a, b;
b = something();
a = ~b;

اشتكى محلل ثابت من الاقتطاع في السطر الأخير، ربما بسبب ذلك b تتم ترقيته إلى int قبل أن يتم قلب البتات الخاصة به وستكون النتيجة من النوع int.

أنا مهتم فقط بالبايت الأخير من int الذي تمت ترقيته - if b كان 0x55، ولست بحاجة a ليكون 0xAA.سؤالي هو، هل تقول مواصفات C أي شيء عن كيفية حدوث الاقتطاع, أم أن التنفيذ محدد/غير محدد؟هل يضمن ذلك a هل سيتم تعيين القيمة التي أتوقعها دائمًا أم يمكن أن يحدث خطأ على منصة مطابقة؟

بالطبع، سيؤدي إرسال النتيجة قبل التعيين إلى إسكات المحلل الثابت، لكنني أريد أن أعرف ما إذا كان من الآمن تجاهل هذا التحذير في المقام الأول.

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

المحلول

يحدث الاقتطاع كما هو موضح في 6.3.1.3/2 من معيار C99

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


مثال لـ CHAR_BIT == 8، sizeof (unsigned char) == 1، sizeof (int) == 4

لذلك، يتم تحويل 0x55 إلى int, ، إلى 0x00000055، ثم تم إلغاءه إلى 0xFFFFFFAA، و

      0xFFFFFFAA
    + 0x00000100 /* UCHAR_MAX + 1 */
    ------------
      0xFFFFFEAA

    ... repeat lots and lots of times ...

      0x000000AA

أو كما هو عادي 0xAA, ، كما كنت تتوقع

نصائح أخرى

يحدد معيار C هذا للأنواع غير الموقعة:

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

في هذه الحالة، إذا كان لديك unsigned char هو 8 بت، فهذا يعني أنه سيتم تخفيض النتيجة إلى modulo 256، وهو ما يعني أنه إذا b كان 0x55, a سوف ينتهي بالفعل كما 0xAA.

ولكن لاحظ أنه إذا unsigned char يكون أوسع أكثر من 8 بتات (وهو أمر قانوني تمامًا)، فستحصل على نتيجة مختلفة.للتأكد من أنك سوف تحصل على المحمولة 0xAA ونتيجة لذلك، يمكنك استخدام:

a = ~b & 0xff;

(يجب تحسين مستوى البت على الأنظمة الأساسية حيث unsigned char هو 8 بت).

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

وسوف تتصرف كما تريد.من الآمن إلقاء القيمة.

هذا المثال الخاص للتعليمات البرمجية آمن.ولكن هناك أسباب للتحذير من التراخي في استخدام عامل التشغيل ~.

السبب وراء ذلك هو أن ~ في المتغيرات الصحيحة الصغيرة يعد خطأً محتملاً في التعبيرات الأكثر تعقيدًا، بسبب ترقيات الأعداد الصحيحة الضمنية في لغة C.تخيل لو كان لديك تعبير مثل

a = ~b >> 4;

ولن يتحول إلى أصفار كما كان متوقعا.

إذا تم تعيين المحلل الثابت الخاص بك ليشمل MISRA-C، فستحصل على سبيل المثال على هذا التحذير لكل عامل ~، لأن MISRA يفرض نتيجة أي عملية على أنواع الأعداد الصحيحة الصغيرة ليتم كتابتها بشكل صريح في النوع المتوقع، وهو حرف غير موقع في هذه الحالة .

لنأخذ حالة جهاز Win32.
العدد الصحيح هو 4 بايت وتحويله إلى حرف سيؤدي تمامًا كما لو تمت إزالة 3 بايت المتبقية.

أثناء قيامك بتحويل char إلى char، لا يهم ما يتم الترويج له.
~b will add 3 bytes at the left change 0s to 1 and then remove... It does not affect your one right byte.

سيتم تطبيق نفس المفهوم على البنى المختلفة (سواء كان جهاز 16 بت أو 64 بت)

على افتراض أن يكون قليلا endian

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