التحقق من وجود معرفات محددة خارجيا في ج
-
29-09-2019 - |
سؤال
لقد واجهت هذه المشكلة أثناء التطوير في Objective-C لنظام التشغيل iOS ، ولكن يجب أن ينطبق هذا على أي رمز C/C ++/Objective-C باستخدام رابط Mac OS X/IOS. الحل مغطى من قبل سؤال آخر, ، لكني مهتم في لماذا.
دعنا نقول أنني أستخدم ارتباطًا بمكتبة تحدد ثابتًا. في ملف الرأس يوجد إعلان مثل هذا:
extern char * const BrandNewIdentifier;
أرغب في تجميع طلبي وتشغيله على نظام مع إصدار سابق من المكتبة ، حيث لا يحتوي هذا الثابت على تعريف ، حتى أكون آمنًا ، لا أفترض أنه تم تعريفه.
الآن ، إذا كانت هناك وظيفة محددة فقط في أحدث إصدار من المكتبة ، يمكنني القيام بذلك:
if (BrandNewFunc) {
BrandNewFunc("foobar", 42);
} else {
printf("Your system does not support some thing.");
}
بدلاً من احتواء عنوان رمز الوظيفة ، BrandNewFunc
يقييم إلى فارغ. أعتقد أن الثابت سيتصرف بنفس الطريقة ، ولكن إذا جربت نفس النمط ، فإن التطبيق يموت أثناء إجراء الشيك (يلقي exc_bad_access على iOS). خاصة:
if (BrandNewIdentifier) ... // blows up here
ما ينجح بدلاً من ذلك هو التحقق من عنوان المعرف:
if (&BrandNewIdentifier) {
printf("You got it!");
}
أستطيع أن أرى المنطق: BrandNewIdentifier
ليس له قيمة ، لذلك يجب أن يفشل الوصول إليها. ولكن لماذا يعمل هذا الجملة في حالة BrandNewFunc
؟ ألا يجب أن أطلب مني التحقق من عنوانه أيضًا؟ أم أنها ثابتة بالفعل ، وهناك شيء أغفلته؟
المحلول
الجزء ذي الصلة من معيار C هو القسم 6.3.2.1 "LVALUES ، المصفوفات ، ومصممي الوظائف". إليك ما تقوله عن الوظائف:
أ مصمم الوظائف هو تعبير له نوع الوظيفة. إلا عندما يكون معامل
sizeof
المشغل أو العامل65 أو أحادي&
المشغل ، مصمم دالة مع إرجاع وظيفة النوع " يكتب"يتم تحويله إلى تعبير له نوع" مؤشر "إلى عودة العمل يكتب’’.الحاشية 65] لأن هذا التحويل لا يحدث ، معامل
sizeof
لا يزال المشغل مصمم وظائف وينتهك القيد في 6.5.3.4 [ed: القيد في 6.5.3.4 يقول أنك لا تقطسsizeof
إلى مصمم الوظائف - إنه خطأ دلالي].
المعرف الذي يسمي الوظيفة هو أبسط نوع من "التعبير الذي له نوع الوظيفة". إذن ما يعنيه هذا ، إذا foo
تم إعلانه كدالة ، المعرف foo
يقيم كمؤشر لتلك الوظيفة ، إلا عندما يكون معامل &
(في هذه الحالة التعبير الأكبر &foo
يقيم كمؤشر لتلك الوظيفة) أو معامل sizeof
(في هذه الحالة التعبير الأكبر ، sizeof(foo)
, ، يثير خطأ ترجمة).
TL ، DR: متى foo
هي وظيفة ، foo
و &foo
معادلة بحكم التعريف. هذه قاعدة خاصة للوظائف. لا يختلف الأمر تمامًا عن القاعدة الخاصة للصفائف ، والتي "تتحلل" أيضًا إلى مؤشرات في العديد من السياقات (هذه القاعدة هي فقرة واحدة من تلك التي نقلت عنها).
جانبا: نعم ، هذا يعني أن مشغل استدعاء الوظائف دائماً يعمل على مؤشر إلى وظيفة. متي pfunc
هو متغير المؤشر إلى الوظيفة ، (*pfunc)()
تتم معالجتها كما لو كانت تقرأ (&(*pfunc))()
... أو فقط pfunc()
.