البرمجة

تجنب التصرفات غير المعرفة في لغة C: حماية البرامج من تجاوز حدود التمثيل الثنائي

في هذا البرنامج الذي تم تقديمه، يظهر بوضوح احتمالية حدوث “undefined behavior” في بيئة لغة البرمجة C. يتساءل الكاتب عن طبيعة هذا السلوك غير المعرف تمامًا عند إدخال المستخدم لرقم “سيء”. هل هو حقًا “undefined behavior” بمعنى أن الشيفرة المصدرية مسموح لها بتحفيز أي مسار في التنفيذ، وأن أي تفاصيل تتعلق بكيفية تنفيذ البرنامج بإمكانها أن تكون غير معروفة ومتغيرة بشكل غير قابل للتنبؤ؟ أم أن هناك نكهة أخرى من غير المعرف تمامًا؟

للإجابة على هذا السؤال الدقيق، دعونا نستعرض السياق العام للمشكلة. البرنامج يقوم بقراءة عدد صحيح من المستخدم باستخدام scanf، ثم يقوم بطباعة قيمة القيمة المطلوبة بواسطة imaxabs. المشكلة تكمن في أن قيمة INTMAX_MIN لا تستطيع أن تمثل نفسها بشكل صحيح في نظام التمثيل الثنائي، مما يؤدي إلى تقاطع بين INTMAX_MIN و-INTMAX_MIN. هذا التقاطع يمثل مصدرًا محتملًا للتصرفات غير المتوقعة وتحفيز “undefined behavior”.

لحماية البرنامج ضد هذا السلوك، يمكن للمبرمج أن يتبع نهجًا دقيقًا وفقًا للمعايير دون الاعتماد على أي افتراضات غير مضمونة. يمكن أن يقوم المبرمج بفحص إدخال المستخدم والتحقق من أن القيمة المدخلة تقع ضمن نطاق قابل للتمثيل بشكل صحيح. يمكن تحقيق ذلك عن طريق استخدام نوع البيانات uintmax_t لتخزين القيمة المدخلة ومن ثم التحقق مما إذا كانت القيمة أقل من INTMAX_MIN أو أكبر من INTMAX_MAX قبل تنفيذ أي عمليات أخرى.

إضافةً إلى ذلك، يمكن للمبرمج توثيق الشيفرة المصدرية بشكل جيد واستخدام تعليقات واضحة لشرح النقاط الدقيقة في البرنامج، بما في ذلك التحذير من المخاطر المحتملة عند التعامل مع حدود التمثيل الثنائي للأعداد.

المزيد من المعلومات

البرنامج المقدم في السياق يتيح للمستخدم إدخال عدد صحيح (integer) في نطاق معين يتم تحديده باستخدام INTMAX_MIN وINTMAX_MAX، ويستخدم نمط البرمجة الذي يعتمد على uintmax_t وجهاز الطباعة الخاص بـ intmax_t.

لفهم المشكلة بشكل أفضل، يجب النظر في خصائص تمثيل الأعداد في الذاكرة. في النظام الثنائي، يمكن تمثيل الأعداد الصحيحة باستخدام بتات بعينها. على سبيل المثال، إذا كان لدينا 8 بت، يمكن تمثيل الأعداد من -128 إلى 127. ولكن عندما ننتقل إلى INTMAX_MIN في نظام 64 بت، يكون التمثيل أكبر بكثير من القيم الصحيحة الممكنة.

في سياق السؤال الأول، يتعلق الأمر بمفهوم “undefined behavior”، وهو مصطلح يستخدم للإشارة إلى أن اللغة لا تحدد بدقة كيف يجب أن يتصرف البرنامج في حالات معينة. في هذا السياق، عند إدخال مستخدم قيمة أقل من INTMAX_MIN، قد يحدث تصرف غير متوقع بحسب تنفيذ المترجم أو البيئة التنفيذية.

بالنسبة للسؤال الثاني، يمكن للمبرمج اتباع مبدأ الحذر والتحقق من صحة الإدخال بشكل كامل دون الاعتماد على أي افتراضات غير مضمونة. يمكن تحقيق ذلك بتخزين قيمة المستخدم باستخدام uintmax_t وفحص ما إذا كانت القيمة داخل النطاق المسموح به قبل القيام بأي عمليات أخرى. يمكن أيضًا توثيق هذا النهج بشكل جيد في الشيفرة المصدرية لتسليط الضوء على التحقق الدقيق الذي يتم به.

في النهاية، يظهر هذا السياق كمثال على أهمية فهم خصائص التمثيل الثنائي وتحقق المبرمج من صحة الإدخال قبل تنفيذ أي عمليات تعتمد على القيمة المدخلة.

زر الذهاب إلى الأعلى