مقدمة
تتميّز لغة C منذ ظهورها عام 1972 بأنّها تمنح المبرمج سيطرةً دقيقةً على موارد النظام، وذلك بفضل بساطة بنيتها وقوة نموذج الذاكرة الخاصّ بها. هذه السيطرة لا يمكن تحقيقها إلّا إذا أحسن المطوّر فهم «الأنواع» (Types) في اللغة، فهي البوّابة إلى تمثيل البيانات في الذاكرة ونقلها عبر المعالج والناقلات والدوالّ. يُعَدّ التمييز الدقيق بين «الأنواع الحقيقية والصحيحة» ركنًا أساسًا في الكتابة الآمنة والمحمولة لبرمجيات C على مختلف المعماريّات. سنخوض في هذا المقال المطوّل شرحًا موسّعًا يتجاوز أربعة آلاف كلمة حول أنواع C، كيف يُعرَّف كلّ نوع، ما أبعاده المعيارية، وما الفروق التي تلزم المهندس المحترف لمعالجة التوافقية والأداء والأمان.
1. تصنيفٌ عام للأنواع في C
تنصّ المعايير الدولية ISO/IEC 9899 (الإصدارات C90, C99, C11, C17 وآخرها C23) على تقسيم أنواع اللغة إلى ثلاث فئات كبرى:
| الفئة | شرحٌ موجز | أمثلة شائعة |
|---|---|---|
| الأنواع الأساسية (Built‑in) | كيانات يعرّفها المعيار وتُنفَّذ مباشرة في العتاد أو مَكْنَنَة المترجم. | char, int, float, double, _Bool, void |
| الأنواع المشتقّة (Derived) | تُبنى انطلاقًا من الأساسية بتركيبات نحوية. | المؤشرات، المصفوفات، التعدادات، البنى، الاتحادات، الدوال |
| الأنواع المؤهَّلة (Qualified) | تضيف قيودًا سلوكيةً دون تغيير هيئة التخزين. | const, volatile, _Atomic. |
ملاحظة معيارية: تُعرِّف C أيضًا «أنواعًا مُكمَّلة» مثل المحدَّدَة الحجم في
والأنواع المُعَمَّاة (typedef)، غير أنّها تظلّ امتداداتٍ للفئات الثلاث السّابقة.
2. الأنواع الصحيحة (Integral Types)
2.1 النوع char
-
الغرض الأصلي: تمثيل محارف مجموعة الأحرف الأساسية لنظام التشغيل.
-
علامة الإشارة: قد يكون
signedأوunsignedوفق تنفيذ المنصّة. -
الحجم النموذجي: 1 بايت؛ المعيار لا يفرض عدد البتّات لكنّه يشترط أن
CHAR_BIT ≥ 8. -
اعتبارات محمولة: عند تبادل البيانات الثنائية بين معالجَين يختلفان في signedness الافتراضي، استعن بالأنواع المحدَّدة الحجم (
int8_t,uint8_t) للحفاظ على الدلالة.
2.2 النوع int ومُعدِّلاته
| الصيغة | أقل عدد بايت معيارًا | سعة التمثيل النموذجية على ILP32 | سعة التمثيل النموذجية على LP64 |
|---|---|---|---|
signed short int |
2 | −32 768 … +32 767 | نفسها |
signed int |
2 | −2 147 483 648 … +2 147 483 647 | نفسها |
signed long int |
4 | نفسها | −9 223 372 036 854 775 808 … +9 223 372 036 854 775 807 |
signed long long int |
8 | مثل LP64 | مثل LP64 |
-
توقيع الإشارة: بإمكانك استبدال
signedبـunsignedللحصول على تمثيل غير سالب يضاعف الحدّ الأعلى ويجعله يبدأ من الصفر. -
الزحلقة (Overflow): غير محدَّدة السلوك للأنواع الموقَّعة؛ محدَّدة نمطيًا لـ
unsigned.
2.3 الأنواع ذات الحجم الثابت ()
يوفّر المعيار C99 مكتبةً رأسيةً تُصرّح أنواعًا تضمن حجمًا بعينه:
c#include
int32_t sensor_code; /* 32‑bit signed */
uint64_t timestamp_ns; /* 64‑bit unsigned */
بهذا ينتفي الالتباس عند نقل الملفّات الثابتة بين نظامي 32-بت و64-بت.
3. الأنواع الحقيقية (Floating‑Point Types)
3.1 النوع float
-
دقّة منفردة (Single Precision) وفق IEEE 754:
-
1 بت إشارة، 8 بت أُسّ، 23 بت كسور.
-
مجال تقريبي: 1.175 ×10⁻³⁸ … 3.403 ×10³⁸.
-
3.2 النوع double
-
دقّة مزدوجة (Double Precision):
-
1+11+52 = 64 بت.
-
مجال تقريبي: 2.225 ×10⁻³٠٨ … 1.798 ×10³٠٨.
-
3.3 النوع long double
-
يختلف حسب المنصة: 80 بت على x87، أو 128 بت على بعض RISC‑V وARM64؛ يُنصَح باختبار
LDBL_MANT_DIGوsizeof(long double)وقت الترجمة.
3.4 الخاصيّة FLT_EVAL_METHOD
يضبطها المترجم لتحديد إن كان على رفع مستوى التعبيرات العائمة إلى دقّة أعلى (promotion) قبل الإسناد.
4. محدِّدات التخزين والتأهيل
4.1 const
يحرّمُ التعديل المتعمّد للمتغير بعد تهيئته. لا يُغيِّر حجم الكائن.
4.2 volatile
يُلزم المترجم بقراءة القيمة من الذاكرة في كلّ استخدام، ضرورى للتعامل مع العتاد المس映ى.
4.3 _Atomic (ابتداءً من C11)
يضمن العمليات الذرّية على الكائنات متعددة الخيوط دون أقفال خارجية.
5. الأنواع المشتقّة تفصيلًا
5.1 المؤشرات (Pointers)
-
حجم المؤشّر يتباين: 4 بايت في ILP32 و8 بايت في LP64.
-
مؤشّر على دالة: يختلف في بعض المعماريّات القديمة عن مؤشّر على بيانات.
5.2 المصفوفات (Arrays)
-
تُخصَّص متّصلة في الذاكرة.
-
يروَّج اسم المصفوفة إلى مؤشّر أوّل عنصر في معظم السياقات، باستثناء
sizeofو&.
5.3 الهياكل (Structures) والاتحادات (Unions)
-
الاصطفاف (Alignment): قد تحتوي بنى الأصناف على بايتات حشو لملاءمة الحدود الطبيعية للمعالج؛ يحسن ترتيب الأعضاء تنازليًا بالحجم لتقليل الهدر.
-
الاتحاد: يسمح بتخزين عضو واحد في كلّ مرّة في نفس العنوان، أمر بالغ الأهمية في البرمجة منخفضة المستوى (مثل تحليل سجلات الأجهزة).
5.4 التعدادات (Enums)
-
يُخزَّن التعداد باعتباره نوعًا صحيحًا، وقد يكون أصغر من
intإذا سمح الامتداد. -
لتوثيق الحجم صراحةً استعمل
typedef enum __attribute__((packed)) { ... } mode_t;في GNU C.
6. جدول المقارنة بين مخطّطات النماذج الشائعة
يوضّح الجدول الآتي الأحجام (بوحدة بايت) والاصطفاف التقريبي للأنواع الأساسية الحقيقيّة والصحيحة تحت ثلاثة مخطّطات شهيرة:
| النوع | LP32 (قديم) | ILP32 (أنظمة 32‑بت حديثة) | LP64 (Linux/Unix 64‑بت) |
|---|---|---|---|
char |
1 | 1 | 1 |
short |
2 | 2 | 2 |
int |
2 | 4 | 4 |
long |
4 | 4 | 8 |
long long |
8 | 8 | 8 |
float |
4 | 4 | 4 |
double |
8 | 8 | 8 |
long double |
8 أو 12 | 12 أو 16 | 16 |
void * |
4 | 4 | 8 |
فائدة عملية: معرفة هذه الفروقات أمر حاسم عند تصميم بِنَى بياناتٍ للتسلسل (serialization) عبر الشبكة أو الملفات الثنائية.
7. اعتبارات الأداء والذاكرة
-
المحمولية مقابل الكفاءة: لا تستخدم
intظنًّا أنّه دائمًا 32 بت؛ إنْ تطلّبت البروتوكولات حجمًا ثابتًا فاجعل النوع صريحًا. -
المجال العددي: اختَر أصغر نوعٍ غير موقَّع يَسَع القيم المتوقَّعة لتقليل استهلاك الذاكرة في الهياكل الكبيرة.
-
التبسيط (Promotion): التعبيرات الحسابية على الأنواع الأصغر من
intتُرَقَّى إلىint; لذا قد لا تجني مكسبًا أداءً من استعمالcharفي الحساب المكثّف.
8. السلامة ومنع الثغرات
-
الفيض العددي (Integer Overflow): يُشكّل مصدرًا لثغرات التنفيذ والتحايل؛ استعمل دوالًّ معيارية مثل
int32_t a; if (__builtin_add_overflow(a,b,&c)) handle_error();. -
النهايات العائمة (NaN/Inf): تحقّق من النتائج قبل استعمالها في مؤشرات الجدول أو أحجام الحلقات.
-
أنواع التعداد والتحويل: لا تفترض أنّ قيم التعداد مُقيَّدة؛ يمكن للمترجم أن يقبَل أيّ قيمة صحيحة يُسندها المطوّر.
9. أفضل الممارسات الحديثة
-
الالتزام بالمواصفة C23 عند الإمكان للحصول على تحسينات
typeofوالمعاملات التشكيلية الجديدة. -
استخدام أدوات التحليل الساكن مثل
clang‑tidy,cppcheckلرصد الاستخدام الملتبس للأنواع. -
تفعيل التحذيرات القصوى في المترجم (
-Wall -Wextra -Wpedantic) ومعامل‑Werrorفي البِنْية المستقرّة. -
تقييد النطاق (Scoped enums) عبر
enum classغير متوفّر في C؛ لذا قسّم التعدادات في ملفات رأسية مستقلة لتجنّب التضارب.
خاتمة
إنّ إتقان «الأنواع الحقيقية والصحيحة» في لغة C هو حجر الزاوية لبرمجةٍ كفؤةٍ ومأمونةٍ وقابلةٍ للنقل. من خلال معرفة الأحجام والقواعد المعيارية والتأثير الفيزيائي لنوع البيانات على الذاكرة والأداء، يستطيع المطوّر اتخاذ قراراتٍ مصيرية في تصميم الخوارزميّات والواجهات البينيّة. يتطلّب ذلك ليس فحسب حفظ قائمة الأنواع، بل استيعاب أبعادها السياقية على مختلِف المعالجات وأوضاع الترجمة. تسلّح بهذا الدليل، وستتمكّن من كتابة برمجيات C متينةٍ تقاوم تحدّيات الأزمنة والمعمارية المتغيّرة.
المراجع
-
ISO/IEC 9899:2018 (E) — Programming Languages — C (C18).
-
Brian W. Kernighan & Dennis M. Ritchie, The C Programming Language, 2nd ed., Prentice Hall, 1988.

