لغز الأحجام: لماذا يتصرف int و long بشكل مختلف على المترجمات المختلفة؟
\n\nكل من درس C++ بجدية، عاجلاً أم آجلاً، واجه هذا اللغز. تكتب كوداً بسيطاً:
\n\n#include <iostream>\n\nint main() {\n std::cout << "حجم int: " << sizeof(int) << " بايت\\n";\n std::cout << "حجم long: " << sizeof(long) << " بايت\\n";\n std::cout << "حجم long long: " << sizeof(long long) << " بايت\\n";\n return 0;\n}\n\nتشغله على حاسوبك المحمول - تحصل على 4, 4, 8. تشغله على خادم Linux - 4, 8, 8. وعلى نظام قديم 16 بت (نعم، لا تزال هذه حية!) - 2, 4, 8. أين الخدعة؟ لماذا تسمح C++، اللغة المشهورة بقوتها وتحكمها، بهذا الغموض؟
\n\nالإجابة بسيطة ومعقدة في نفس الوقت: معيار C++ يترك عمداً أحجام الأنواع الصحيحة لتقدير التطبيق. هذا ليس خطأ، بل ميزة تسمح للغة بالعمل على أي جهاز - من المتحكمات الدقيقة إلى الحواسيب الفائقة. ولكن بالنسبة للمطور، هذا يعني شيئاً واحداً: إذا كنت تكتب كوداً قابلاً للنقل، فلا يمكنك الاعتماد على أحجام محددة.
\n\nدعنا نفهم ما يضمنه معيار C++ فعلياً (بدءاً من C++98 وحتى C++23) وكيف لا تقع في فخ الاعتماد على المنصة.
\n\nماذا يضمن معيار C++؟ الأحجام الدنيا والتسلسل الهرمي
\n\nبدلاً من أن يقول "int هو 4 بايت"، يحدد المعيار نطاقات القيم الدنيا وتسلسلاً هرمياً صارماً للأحجام. إليك القواعد الأساسية من مسودة المعيار (القسم [basic.fundamental]):
\n\n- \n
- الحجم الأدنى لـ
char: 1 بايت (8 بت، على الرغم من أن البايت رسمياً في C++ يمكن أن يكون أكبر). \n - التسلسل الهرمي للأحجام:
sizeof(char) ≤ sizeof(short) ≤ sizeof(int) ≤ sizeof(long) ≤ sizeof(long long). \n - الحد الأدنى للبتات:\n
- \n
short: 16 بت على الأقل. \n int: 16 بت على الأقل. \n long: 32 بت على الأقل. \n long long: 64 بت على الأقل (أضيف في C++11). \n
\n - حجم
int: يوصي المعيار بأن يكونintذا "حجم طبيعي" للهندسة المعمارية المستهدفة (عادة 4 بايت على أنظمة 32/64 بت). \n
لاحظ: long يمكن أن يساوي int (على Windows 32 بت) أو long long (على Linux 64 بت). هذا قانوني تماماً!
مثال عملي: التحقق على نظامك
\n\nشغّل هذا الكود وقارن النتائج مع زملائك من أنظمة تشغيل مختلفة:
\n\n#include <iostream>\n#include <climits> // من أجل INT_MAX, LONG_MAX إلخ.\n\nint main() {\n std::cout << "الأحجام بالبايت:\\n";\n std::cout << "short: " << sizeof(short) << "\\n";\n std::cout << "int: " << sizeof(int) << "\\n";\n std::cout << "long: " << sizeof(long) << "\\n";\n std::cout << "long long: " << sizeof(long long) << "\\n\\n";\n\n std::cout << "القيم القصوى:\\n";\n std::cout << "INT_MAX: " << INT_MAX << "\\n";\n std::cout << "LONG_MAX: " << LONG_MAX << "\\n";\n std::cout << "LLONG_MAX: " << LLONG_MAX << "\\n";\n return 0;\n}\n\nسترى أنه على Windows (MSVC) غالباً ما يساوي long 4 بايت، بينما على Linux (GCC/Clang) يساوي 8 بايت. هذا مصدر كلاسيكي للأخطاء عند نقل الكود بين المنصات.
لماذا لا يحدد المعيار الأحجام؟ السياق التاريخي
\n\nتخيل سبعينيات القرن الماضي. كانت المعالجات 8 بت، 16 بت، و 32 بت كانت بالكاد تظهر. مبتكرو لغة C (و