Menu
flag Ar iconالعربيةdown icon

أنواع البيانات في لغة C: ‏int وfloat وchar وdouble وغيرها

لكل متغيّر في C نوع يثبّت حجمه وما يمكنه حمله. إليك كل الأنواع الأساسية وأحجامها الحقيقية، والموقّع مقابل غير الموقّع، وsizeof، وlimits.h، وما يحدث عند الفيضان.

تحتوي هذه الصفحة على محررات قابلة للتشغيل - حرّر، شغّل، وشاهد النتيجة فوراً.

لكل متغيّر في C نوع، تختاره حين تعرّفه ويثبت مدى حياته. ويقرّر النوع ثلاثة أشياء: كم بايتًا يشغل المتغيّر، وكيف تُفسَّر تلك البايتات، وأي العمليات لها معنى عليه.

وقائمة أنواع C قصيرة. والتعقيد في المُعدِّلات.

الأنواع الأساسية الأربعة

  • char يحمل بايتًا واحدًا. ويُستخدم للمحارف المفردة ('A')، ولبايتات السلسلة النصية، وأحيانًا كعدد صحيح صغير جدًا.
  • int هو حصان العمل للأعداد الصحيحة. عدّادات الحلقات والأحجام والمعرّفات.
  • float و**double** يحملان الأعداد الحقيقية. وdouble ذو دقّة تقارب الضعف.
  • void هو النوع الرابع بمعنى ما، لكنه يعني "لا قيمة" - فلا يمكنك تعريف متغيّر void، بل استخدامه فقط كنوع إرجاع دالة أو قائمة وسائط فارغة أو مؤشّر بلا نوع.

لاحظ اللاحقة f في 3.14f. فبدونها تكون القيمة الحرفية من نوع double، وإسنادها إلى float يفقد الدقّة بصمت. وبعض المترجمات تحذّر من ذلك.

المُعدِّلات: ‏short وlong وunsigned

تأتي الأنواع الصحيحة الأساسية مع مُعدِّلات تغيّر الحجم أو الإشارة.

لكل نوع صحيح محدّد تنسيق خاص به: %hd لـ short، و%d لـ int، و%ld لـ long، و%lld لـ long long، و%u لغير الموقّع. واستخدام الخاطئ منها سلوك غير معرَّف، لا خطأ تقريب.

unsigned تزيل بتّ الإشارة وتضاعف المدى الموجب. فـ unsigned int يحمل من 0 إلى نحو 4.3 مليار بدل -2.1 إلى +2.1 مليار. وهو الخيار الصحيح لما لا يمكن أن يكون سالبًا فعلًا - الأحجام، وعدد البايتات، وأنماط البتّات - وفخّ لأي شيء قد يُطرح إلى ما دون الصفر.

وsigned هي الافتراض لـ int وshort وlong وlong long، فلا تكتبها تقريبًا أبدًا. والموضع الوحيد الذي تهمّ فيه هو char: فكون char المجرّد موقّعًا أو غير موقّع يحدّده التطبيق، لذا اكتب signed char أو unsigned char حين تهمّ الإشارة.

الأحجام: ما تحصل عليه فعلًا

يحدّد معيار C حدودًا دنيا، لا أحجامًا مضبوطة. وعلى أي جهاز حديث بـ 64 بتًا يعمل بلينكس أو ماك أو ويندوز سترى هذا:

النوعالحجم المعتادالمدى المعتاد
char1 بايت‎-128 إلى 127 (أو 0 إلى 255)
short2 بايت‎-32,768 إلى 32,767
int4 بايت‎-2,147,483,648 إلى 2,147,483,647
long8 بايت (4 على ويندوز)نحو ‎±9.2 كوينتيليون
long long8 بايتنحو ‎±9.2 كوينتيليون
float4 بايت‎~7 أرقام معنوية
double8 بايت‎~15 رقمًا معنويًا
long double16 بايت (يتباين)أكثر من double

وصفّ long هو الذي يوقع الناس: فهو 8 بايتات على لينكس وماك، و4 بايتات على ويندوز بـ 64 بتًا. والشيفرة التي تفترض أن long يمكنه حمل قيمة بـ 64 بتًا ليست محمولة. استخدم long long، أو الأنواع مضبوطة العرض من stdint.h (‏int32_t وuint64_t) حين يكون الحجم جزءًا من المتطلّب.

sizeof: اسأل المترجم

لا تخمّن حجمًا أبدًا - قِسْه:

sizeof عامل لا دالة، ويُقيَّم وقت الترجمة. ويُنتج قيمة من نوع size_t، تُطبع بـ %zu.

وsizeof(char) مضمون أن يساوي 1 بالضبط - فذلك هو تعريف البايت في C. وكل ما عداه يُقاس نسبةً إليه.

limits.h وfloat.h

المدَيات المضبوطة لمترجمك متاحة كثوابت مسمّاة:

هذه هي القيم التي تقارن بها حين تحتاج أن تعرف هل ستفيض عملية ما. وفحص if (a > INT_MAX - b) قبل حساب a + b هو كيف تكتشف الفيضان قبل وقوعه - وهو أمر مهمّ، لأنك لا تستطيع اكتشاف فيضان القيم الموقّعة بعده.

فيضان الأعداد الصحيحة

ما يحدث حين تتجاوز قيمة مدى نوعها يعتمد كليًا على الإشارة.

فيضان غير الموقّع معرَّف: تلتفّ القيمة بمقياس 2^N.

والحالة الثانية مصدر حقيقي للعلل. فحلقة مثل for (unsigned i = n - 1; i >= 0; i--) لا تنتهي أبدًا، لأن القيمة غير الموقّعة دائمًا >= 0.

وفيضان الموقّع سلوك غير معرَّف. ليس "يلتفّ" - بل غير معرَّف. ويُسمَح للمترجم بافتراض أنه لا يحدث أبدًا والتحسين على ذلك الأساس، ما يعني أن فحص فيضان مكتوبًا بعد وقوعه يمكن حذفه:

int sum = a + b;
if (sum < a) { /* قد يحذف المترجم هذا كليًا */ }

افحص قبلًا، باستخدام الحدود:

if (b > 0 && a > INT_MAX - b) {
    /* a + b ستفيض - عالج ذلك */
}

دقّة الفاصلة العائمة

يخزّن float وdouble الأعداد ثنائيًا، ومعظم الكسور العشرية ليس لها صيغة ثنائية مضبوطة - تمامًا كما أن 1/3 ليس له صيغة عشرية مضبوطة.

والقاعدة المترتّبة: لا تقارن أبدًا قيم الفاصلة العائمة بـ ==. قارن الفرق المطلق بهامش تسامح صغير بدلًا من ذلك.

ولا تستخدم الفاصلة العائمة للنقود أبدًا. خزّن السنتات كعدد صحيح؛ فـ long long من السنتات مضبوط حيث لا يكون double من الدولارات كذلك.

اختيار النوع

قائمة قرار قصيرة تغطّي معظم الشيفرات:

  • الأعداد الصحيحة: int ما لم يكن لديك سبب. فهو النوع الذي يعالجه المعالج بأعلى كفاءة، والنوع الذي بُنيت حوله كل قواعد الحساب.
  • أي شيء أكبر من ملياري وحدة: long long، أو int64_t من stdint.h.
  • الأحجام والأطوال وفهارس المصفوفات من sizeof أو strlen: size_t. فهو غير موقّع ومضمون أن يتّسع لأي كائن.
  • الأعداد العشرية: double. واستخدم float فقط لتنصيف الذاكرة في المصفوفات الكبيرة أو على عتاد مضمّن بلا وحدة دقّة مزدوجة.
  • المحارف المفردة والبايتات الخام: char للنصّ، وunsigned char للبيانات الثنائية.
  • صحيح/خطأ: bool من stdbool.h - انظر القيم المنطقية في C.
  • عروض بتّات مضبوطة (صيغ الملفات، بروتوكولات الشبكة، مسجّلات العتاد): stdint.h - uint8_t وint16_t وuint32_t وهكذا.

خلط الأنواع

حين تدمج نوعين مختلفين في تعبير واحد، تحوّلهما C من خلف ظهرك قبل إجراء الحساب. وذلك مفيد عادةً وكارثي أحيانًا:

الأول قسمة صحيحة: فكلا المعاملين int، فتكون النتيجة int ويُسقَط الكسر. والثالث أسوأ - فمقارنة قيمة موقّعة بأخرى غير موقّعة تحوّل الموقّعة إلى غير موقّعة، فتحيل -1 إلى عدد موجب ضخم.

وتلك القواعد التحويلية، وكيفية السيطرة عليها بتحويلات صريحة، هي موضوع تحويل الأنواع في C.

الأسئلة الشائعة

ما أنواع البيانات الأساسية في لغة C؟

أربعة أنواع أساسية: char للمحارف المفردة والبايتات، وint للأعداد الصحيحة، وfloat وdouble للأعداد العشرية. وتغيّر المُعدِّلات حجمها وإشارتها - short وlong وlong long وsigned وunsigned - فتُنتج المجموعة الكاملة.

كم بايتًا يشغل int في لغة C؟

أربعة بايتات (32 بتًا) في الغالب الأعمّ على أنظمة سطح المكتب والخوادم الحديثة، بمدى يقارب -2.1 مليار إلى 2.1 مليار. ولا يضمن المعيار سوى بايتين على الأقل، والمتحكّمات الدقيقة ذات 16 بتًا تستخدم بايتين فعلًا. استخدم sizeof(int) إن احتجت اليقين.

ما الفرق بين float وdouble في لغة C؟

float أربعة بايتات بنحو 7 أرقام عشرية معنوية؛ وdouble ثمانية بايتات بنحو 15. وdouble هو الافتراضي للقيم الحرفية ذات الفاصلة العائمة وللدوال الرياضية، وما لم تكن تخزّن ملايين القيم أو تستهدف رقاقة مضمّنة، فإن double هو الخيار الصحيح.

ماذا يحدث حين يفيض int في لغة C؟

بالنسبة إلى int موقّع، الفيضان سلوك غير معرَّف - فقد يلتفّ المترجم أو يشبع القيمة أو يحذف الفحص كليًا بالتحسين. أما بالنسبة إلى int غير موقّع فهو معرَّف تمامًا: تلتفّ القيمة بمقياس 2^N، فتكون UINT_MAX + 1 صفرًا. لا تعتمد أبدًا على فيضان القيم الموقّعة.

Coddy programming languages illustration

تعلّم البرمجة مع Coddy

ابدأ الآن