في عملية نقل برنامج من نظام التشغيل Windows إلى نظام التشغيل OS X، والذي تم كتابته أصلاً بلغة C++، وجدت نفسي مستمتعًا بالتحدي الفني لأنني لا أعمل كثيرًا مع عائلة اللغات C، وقد استمتعت بالاستفادة من Objective C++ في عملية التحويل.
لكنني واجهت شيئًا غريبًا في كود المصدر الخاص بنظام التشغيل Windows، وأتساءل عما إذا كان هذا ممارسة قياسية. يتوقع أن تقوم واجهة التطبيق (API) التي نعمل عليها على كل من نظامي التشغيل Windows و OS X بتمرير قيمة unsigned short إلى طريقة معينة لكائن معين. قام المطور الأصلي لنظام Windows بإنشاء الدالة التالية لحساب هذه القيمة:
cppstatic unsigned short hashcode(const char* value) {
int h = 0;
unsigned long length = strlen(value);
for (int i = 0; i < length; i++) {
h = (31 * h) + value[i];
}
return h;
}
يرجى ملاحظة أن الدالة تقوم بإرجاع unsigned short
، ولكن المتغير الذي يتم إرجاعه هو من نوع int
. لقد قمت بفحص التوثيق، ووجدت أن نظامي OS X و Windows يعرفان كل من unsigned short
بـ 2 بايت و int
بـ 4 بايت.
قيمة تمريرها إلى هذه الدالة، إذا لم يتم أخذ نوع البيانات في اعتباره، تؤدي إلى إرجاع الدالة لأرقام كبيرة جدًا، تحتوي على عشرات الأرقام في بعض الحالات. في حالة واحدة، حيث قمت بتكرار الخوارزمية في لغة أخرى مع أنواع أقل تشددًا، حصلت على قيمة 2081357292912430390912
. عندما قمت بتضمين الدالة أعلاه في أداة سطر الأوامر، حصلت على نفس السلسلة تعود بقيمة 40576
، وأفترض أن ذلك هو الإصدار المقتصر من القيمة الأطول.
لدي سؤالين، أولاً، لماذا، إذا كان من المفترض أن تُعلن hashcode
لإرجاع unsigned short
وفعلاً يتم إرجاع int
، لا يتم الشكوى من قبل المترجم؟ أليس هذا هو الغرض من التصريحات الصارمة لنوع البيانات في المقام الأول؟ لضمان أن تتلقى الدوال والأساليب الأنواع المتوقعة وترجعها؟
وثانيًا، هل هذا الانقطاع هو ممارسة قياسية؟ يبدو غريبًا لي، أولاً بالنسبة للاستفادة من التحويل التلقائي، ولكن أيضًا لعدم وجود توضيح بشأن كيفية حدوث هذا التقليص (وليس لدي وصول إلى المطور الأصلي لطلب المزيد من التوضيح). نظرًا لأنه لم يُعلق على أنه شيء “خاص”، فإنه ربما يكون ببساطة تقليدًا قياسيًا في لغات C/C++؟
المزيد من المعلومات
لفهم هذا السيناريو بشكل أعمق، يمكننا التركيز على جوانب محددة تتعلق بتصميم اللغة وعادات البرمجة في C++.
أولاً، بالنسبة للسؤال الأول حول عدم تحذير المترجم بشأن اختلاف نوع القيمة المُرجَعة من الدالة، يعود ذلك جزئيًا إلى مرونة C++ في التعامل مع التحويلات الضمنية (implicit conversions) والتحويلات التلقائية بين الأنواع. في حالة الدالة hashcode
، يُرجى مراعاة أن قيمة h
التي تُعيد تأتي من نوع int
، ولكن تتم تحويلها بشكل ضمني إلى unsigned short
عندما تُرجَع. هذا يعني أن التحويل يحدث بشكل تلقائي، والمترجم لا يُعطي إنذارًا لأن هناك تحويلًا آمنًا ضمنيًا بين الأنواع.
ثانيًا، بالنسبة للسؤال الثاني حول ما إذا كانت هذه العملية نوعًا من الممارسات القياسية، يمكن أن تعتمد هذه السلوكيات على الحالة الخاصة للتطبيق أو المكتبة المستخدمة. في بيئة برمجية معينة، قد يكون لديهم سبب معين للتحويل الضمني من int
إلى unsigned short
، ربما لتوفير توافق أفضل مع واجهة معينة أو لتحقيق أداء أفضل في حالة معينة.
من الجانب الآخر، يعتبر استخدام التحويل التلقائي بين أنواع البيانات المختلفة دون توضيح أو تعليق أمرًا يمكن أن يكون مشكوكًا فيه، خاصةً عند التعامل مع تطبيقات حيث يكون التحكم الدقيق في النوع أمرًا مهمًا لضمان سلامة البرنامج. قد يكون توضيح الرمز ووضع تعليقات توضيحية لهذا النوع من التحويلات ذو أهمية كبيرة لتسهيل فهم الشيفرة وصيانتها في المستقبل.
في النهاية، يمكن أن يكون الأمر مرتبطًا بتفضيلات المطورين الأصليين وقوانين البرمجة في الفريق، وهذا يظل قرارًا تقنيًا قد يعتمد على سياق العمل الخاص بالمشروع ومتطلباته.