فخ للغافلين: لماذا unsigned int هي قنبلة موقوتة؟
\n\nكل مطور C++ عاجلاً أم آجلاً يواجه موقفًا تتصرف فيه الأرقام مثل الأرانب الشريرة - تقفز بلا نهاية من الموجب إلى الصفر. الحديث يدور عن تجاوز unsigned int. على عكس نظيرها المُشار إليه (signed int)، فإن تجاوز unsigned في C++ مُحدد بدقة بالمعيار - فهو ليس سلوكًا غير محدد (UB). الرقم ببساطة يلتف حول modulo 2N. لكن هذا لا يجعل الخطأ أقل فتكًا.
تخيل: أنت تحسب رصيد حساب، أو عدد العناصر في مصفوفة، أو وقت تشغيل مؤقت. تجاوز واحد عشوائي - وينهار منطق التطبيق. السؤال من العنوان "How do I detect unsigned integer overflow?" جمع آلاف المشاهدات على Stack Overflow ليس من فراغ. دعنا نحلل ثلاث طرق لاكتشاف التجاوز: من الساذج (لكنه يعمل) إلى الاحترافي.
\n\nلماذا لا تعمل الفحوصات القياسية؟
\n\nأول ما يخطر ببال المبتدئ:
\n\nunsigned int a = UINT_MAX;\nunsigned int b = 1;\nif (a + b < a) // فحص ساذج\n std::cout << "تجاوز!";\n\nهذا الكود يعمل، ولكن فقط للجمع. بالنسبة للضرب أو الطرح أو الأنواع المختلطة، ينهار المنطق. بالإضافة إلى ذلك، قد يعتبر المترجم هذا الفحص زائدًا ويحذفه أثناء التحسين. خاصة إذا كانت الأنواع مُشار إليها. لا تعتمد على السحر - اكتب بوضوح.
\n\nالطريقة رقم 1: الحساب قبل العملية (Pre-check)
\n\nالطريقة الأكثر موثوقية هي التحقق من إمكانية التجاوز قبل تنفيذ العملية. لجمع رقمين غير مُشار إليهما، الشرط بسيط:
\n\nإذا كان a + b قد يتجاوز، فإن a > (UINT_MAX - b).
#include <climits>\n#include <iostream>\n\nbool will_add_overflow(unsigned int a, unsigned int b) {\n return a > UINT_MAX - b;\n}\n\nint main() {\n unsigned int x = 4000000000;\n unsigned int y = 500000000;\n \n if (will_add_overflow(x, y)) {\n std::cerr << "خطأ: تجاوز أثناء الجمع!\\n";\n } else {\n std::cout << "النتيجة: " << x + y << "\\n";\n }\n return 0;\n}\n\nالضرب - أكثر تعقيدًا
\nبالنسبة للضرب، الفحص أكثر دقة: a > UINT_MAX / b (ولا تنسَ القسمة على صفر).
bool will_mult_overflow(unsigned int a, unsigned int b) {\n if (b == 0) return false; // الضرب في صفر - آمن\n return a > UINT_MAX / b;\n}\n\nالإيجابيات: توافق عبر المنصات، تحكم كامل، لا تبعيات خفية.
\nالسلبيات: تحتاج لكتابة دوال منفصلة لكل عملية. يصبح الكود ضخمًا.
الطريقة رقم 2: الفحص بعد العملية (Post-check)
\n\nمعيار C++ يضمن أنه بالنسبة للأنواع unsigned، نتيجة العملية هي (a + b) mod 2^N. لذلك يمكننا تنفيذ العملية ثم التحقق مما إذا كانت القيمة قد "التفت".
#include <iostream>\n#include <limits>\n\ntemplate<typename T>\nbool add_overflow(T a, T b, T& result) {\n result = a + b;\n return result < a; // الحيلة الأساسية\n}\n\nint main() {\n unsigned int res;\n if (add_overflow(4000000000u, 500000000u, res)) {\n std::cout << "تم تسجيل التجاوز!\\n";\n } else {\n std::cout << "موافق: " << res << "\\n";\n }\n return 0;\n}\n\nهام: هذه الحيلة تعمل فقط إذا كان a و b من نفس النوع غير المُشار إليه. بالنسبة لـ uint32_t - ممتاز. بالنسبة لمزيج من unsigned int و int - فشل.
فخ الطرح
\nبالنسبة للطرح، الشرط معاكس: result > a.
template<typename T>\