سؤال

بالنظر إلى أن INTs الموقعة وغير الموقعة تستخدم نفس السجلات ، وما إلى ذلك ، وتفسير أنماط البتات بشكل مختلف ، و C chars هي في الأساس فقط 8 بت ، ما هو الفرق بين chars الموقّعة وغير الموقعة في C؟ أفهم أن توقيع char محدد للتنفيذ ، وأنا ببساطة لا أستطيع أن أفهم كيف يمكن أن يحدث فرقًا ، على الأقل عند استخدام Char لعقد سلاسل بدلاً من القيام بالرياضيات.

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

المحلول

لن تحدث فرقا للسلاسل. ولكن في C يمكنك استخدام char للقيام بالرياضيات ، عندما يحدث فرق.

في الواقع ، عند العمل في بيئات الذاكرة المقيدة ، مثل تطبيقات 8 بتات المدمجة ، غالبًا ما يتم استخدام char للقيام بالرياضيات ، ثم يحدث فرقًا كبيرًا. هذا لأنه لا يوجد byte اكتب افتراضيًا في C.

نصائح أخرى

من حيث القيم التي يمثلونها:

شار غير موقعة:

  • يمتد نطاق القيمة 0..255 (00000000..11111111)
  • تتدفق القيم حول الحافة المنخفضة على النحو التالي:

    0 - 1 = 255 (00000000 - 00000001 = 11111111)

  • تتدفق القيم حول الحافة العالية على النحو التالي:

    255 + 1 = 0 (11111111 + 00000001 = 00000000)

  • مشغل التحول الأيمن bitwise (>>) هل تحول منطقي:

    10000000 >> 1 = 01000000 (128 / 2 = 64)

وقعت char:

  • يمتد نطاق القيمة -128..127 (10000000..01111111)
  • تتدفق القيم حول الحافة المنخفضة على النحو التالي:

    -128 - 1 = 127 (10000000 - 00000001 = 01111111)

  • تتدفق القيم حول الحافة العالية على النحو التالي:

    127 + 1 = -128 (01111111 + 00000001 = 10000000)

  • مشغل التحول الأيمن bitwise (>>) هل تحول الحساب:

    10000000 >> 1 = 11000000 (-128 / 2 = -64)

لقد قمت بتضمين التمثيلات الثنائية لإظهار أن سلوك التغليف القيمة هو الحساب الثنائي النقي ومتسق وليس له أي علاقة بشار يتم توقيعه/غير موقّع (توقع التحولات الصحيحة).

تحديث

بعض السلوك الخاص بالتنفيذ المذكور في التعليقات:

#include <stdio.h>

int main(int argc, char** argv)
{
    char a = 'A';
    char b = 0xFF;
    signed char sa = 'A';
    signed char sb = 0xFF;
    unsigned char ua = 'A';
    unsigned char ub = 0xFF;
    printf("a > b: %s\n", a > b ? "true" : "false");
    printf("sa > sb: %s\n", sa > sb ? "true" : "false");
    printf("ua > ub: %s\n", ua > ub ? "true" : "false");
    return 0;
}


[root]# ./a.out
a > b: true
sa > sb: true
ua > ub: false

من المهم عند فرز السلاسل.

هناك فرقان. الأهم من ذلك ، إذا قمت بتدفق النطاق الصحيح من char من خلال تعيينه عددًا صحيحًا كبيرًا أو صغيرًا ، وتم توقيع char ، فإن القيمة الناتجة محددة أو حتى بعض الإشارات (في C) يمكن أن ترتفع ، كما هو الحال بالنسبة لجميع الأنواع الموقعة . قارن عن ذلك مع الحالة عندما تقوم بتعيين شيء كبير أو صغير إلى شار غير موقّع: القيمة التي تدور حولها ، ستحصل على دلالات محددة بدقة. على سبيل المثال ، تعيين -1 إلى char غير موقعة ، ستحصل على uchar_max. لذلك كلما كان لديك بايت كما في رقم من 0 إلى 2^char_bit ، يجب عليك حقًا استخدام char غير موقعة لتخزينه.

تحدث العلامة أيضًا فرقًا عند الانتقال إلى وظائف Vararg:

char c = getSomeCharacter(); // returns 0..255
printf("%d\n", c);

افترض أن القيمة المخصصة لـ C ستكون كبيرة جدًا بحيث لا يمكن تمثيلها ، ويستخدم الجهاز تكملة اثنين. يتصرف العديد من التنفيذ للحالة التي تقوم بتعيين قيمة كبيرة جدًا لـ Char ، حيث لن يتغير النمط البت. إذا كان بإمكان INT تمثيل جميع قيم char (وهو بالنسبة لمعظم التطبيقات) ، فسيتم ترقية char إلى int قبل المرور إلى printf. لذلك ، فإن قيمة ما تم تمريره ستكون سلبية. الترويج إلى int سيحتفظ بهذه العلامة. لذلك سوف تحصل على نتيجة سلبية. ومع ذلك ، إذا لم يتم تعيين char ، فإن القيمة غير موقعة ، وسيؤدي الترويج إلى int إلى إيجابية. يمكنك استخدام char غير موقعة ، ثم ستحصل على سلوك محدد بدقة لكل من المهمة للمتغير ، والتمرير للطباعة الذي سيطبع شيئًا إيجابيًا.

لاحظ أن char ، غير موقعة وموقعة جميعها على الأقل 8 بت واسعة. لا يوجد أي شرط أن تشار بالضبط 8 بت واسعة. ومع ذلك ، بالنسبة لمعظم الأنظمة الصحيحة ، ولكن بالنسبة للبعض ، ستجد أنها تستخدم 32 بت. يتم تعريف بايت في C و C ++ على حجم char ، لذلك لا يكون البايت في C أيضًا 8 بتات بالضبط.

هناك اختلاف آخر هو أنه في C ، يجب ألا يكون لدى char غير موقّع أجزاء حشوة. أي إذا وجدت char_bit هو 8 ، فيجب أن تتراوح قيم char غير موقعة من 0 .. 2^char_bit-1. وينطبق الشيء نفسه على char إذا كان غير موقّع. بالنسبة إلى char الموقّع ، لا يمكنك أن تفترض أي شيء عن نطاق القيم ، حتى لو كنت تعرف كيف يقوم المترجم الخاص بك بتنشيط الأشياء (تكملة اثنين أو الخيارات الأخرى) ، فقد يكون هناك وحدات حشو غير مستخدمة فيه. في C ++ ، لا توجد أجزاء حشوة لجميع أنواع الأحرف الثلاثة.

"ماذا يعني أن يتم توقيع شار؟"

تقليديًا ، تتكون مجموعة حرف ASCII من تشفير الأحرف 7 بت. (على عكس 8 بت ebcidic.)

عندما تم تصميم لغة C وتنفيذها ، كانت هذه مشكلة مهمة. (لأسباب مختلفة مثل نقل البيانات عبر أجهزة المودم التسلسلي.) يستخدم البت الإضافي مثل التكافؤ.

تصادف أن "شخصية موقعة" مثالية لهذا التمثيل.

البيانات الثنائية ، OTOH ، تأخذ ببساطة قيمة كل "جزء" من 8 بت من البيانات ، وبالتالي لا توجد حاجة إلى علامة.

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

  • التحويل إلى int أكبر
  • وظائف المقارنة

الشيء السيئ هو أن هذه لن تعضك إذا كانت جميع بيانات السلسلة الخاصة بك 7 بت. ومع ذلك ، فإنه يعد بأن يكون مصدرًا لا ينتهي للأخطاء الغامضة إذا كنت تحاول جعل برنامج C/C ++ الخاص بك نظيفًا 8 بت.

تعمل التوقيع إلى حد كبير بنفس الطريقة charS كما هو الحال في أنواع لا يتجزأ الأخرى. كما لاحظت ، فإن chars هي في الحقيقة مجرد أعداد صحيحة بايت. ((ليس بالضرورة 8 بت, ، على أية حال! هناك فرق؛ قد يكون البايت أكبر من 8 بت على بعض المنصات ، و charترتبط S إلى البايتات بسبب تعريفات char و sizeof(char). ال CHAR_BIT الماكرو ، محدد في <limits.h> أو C ++ <climits>, ، سوف أخبركم كم عدد البتات في char.).

بالنسبة للسبب الذي تريده حرفًا مع علامة: في C و C ++ ، لا يوجد نوع قياسي يسمى byte. إلى المترجم ، charS هي بايت والعكس بالعكس ، ولا يميز بينهما. في بعض الأحيان ، رغم أنك تريد - أحيانًا أنت يريد الذي - التي char لكي تكون رقمًا بايت واحد ، وفي هذه الحالات (لا سيما مدى صغر حجم البايت A) ، فإنك تهتم أيضًا بما إذا كان الرقم موقّعًا أم لا. لقد استخدمت شخصيا التوقيع (أو غير موقعة) لأقول ذلك char هو (رقمي) "بايت" بدلاً من شخصية ، وسيتم استخدامه عدديًا. بدون علامة محددة ، ذلك char حقا شخصية ، ويهدف إلى استخدامها كنص.

اعتدت أن أفعل ذلك ، بل. الآن الإصدارات الأحدث من C و C ++ لديها (u?)int_least8_t (حاليا typedef'd في <stdint.h> أو <cstdint>) ، والتي تكون أكثر صراحة (على الرغم من أنها عادة ما تكون فقط typedefs لتوقيعها وغير موقعة char الأنواع على أي حال).

الموقف الوحيد الذي يمكنني أن أتخيل أن هذه مشكلة هو إذا اخترت القيام بالرياضيات على chars. من القانوني تمامًا كتابة الرمز التالي.

char a = (char)42;
char b = (char)120;
char c = a + b;

اعتمادًا على توقيع char ، يمكن أن تكون C واحدة من قيمتين. إذا تم عدم موقعة Char ، فسيكون C (char) 162. إذا تم توقيعها ، فستكون هذه حالة فائض حيث أن القيمة القصوى لـ char موقّعة هي 128. أعتقد أن معظم التطبيقات ستعود فقط (char) -32.

شيء واحد حول chars الموقعة هو أنه يمكنك اختبار C> = '' (مساحة) وتأكد من أنه char ascii قابلة للطباعة طبيعية. بالطبع ، إنه ليس محمولًا ، لذلك ليس مفيدًا جدًا.

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