سؤال

لقد واجهت هذه المشكلة أثناء التطوير في 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().

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top