سؤال

النظر في هذا الرمز.

#define A 5
#define B 3

int difference = A - B;

هل يتم ترميز قيمة "الفرق" كـ "2" في وقت الترجمة، أم أنه يتم حسابها في وقت التشغيل؟

هل كانت مفيدة؟

المحلول

ال A و B وحدات الماكرو هي نوع من التشتيت.هذا:

#define A 5
#define B 3

int difference = A - B;

يعادل بالضبط هذا:

int difference = 5 - 3;

لذلك دعونا نناقش هذا الأخير.

5 - 3 هو التعبير المستمر, ، وهو تعبير "يمكن تقييمه أثناء الترجمة بدلاً من وقت التشغيل، وبالتالي يمكن استخدامه في أي مكان قد يكون فيه الثابت".إنه أيضًا تعبير *عدد صحيح ثابت".على سبيل المثال، يجب أن تكون تسمية الحالة عبارة عن تعبير عدد صحيح ثابت، لذا يمكنك كتابة إما ما يلي:

switch (foo) {
    case 2: /* this is a constant */
    ...
}

أو هذا:

switch (foo) {
    case 5 - 3: /* this is a constant expression */
    ...
}

لكن لاحظ أن التعريف يقول ذلك يمكن ان يكون تقييمها أثناء الترجمة، وليس أنه يجب أن يكون.هناك بعض السياقات التي تتطلب تعبيرات ثابتة، وفي تلك السياقات التعبير يجب يتم تقييمها في وقت التجميع.

لكن بافتراض ذلك difference تم الإعلان عنه داخل بعض الوظائف، فإن المُهيئ ليس واحدًا من تلك السياقات.

أي مترجم يستحق ما تدفعه مقابله (حتى لو كان مجانيًا) سوف ينخفض 5 - 3 ل 2 في وقت الترجمة، وإنشاء التعليمات البرمجية التي تخزن القيمة 2 في difference.ولكن ليس مطلوبا القيام بذلك.يحدد معيار C سلوك من البرامج؛ولا يحدد كيفية تنفيذ هذا السلوك.ولكن من الآمن أن نفترض أن أي مترجم تستخدمه سوف يحل محله 5 - 3 بواسطة 2.

حتى لو كتبت:

int difference = 2;

يمكن للمترجم بشكل قانوني إنشاء تعليمات برمجية تقوم بتحميل القيمة 5 في السجل، ويطرح 3 منه، ويخزن محتويات السجل فيه difference.قد يكون هذا أمرًا سخيفًا، لكن معيار اللغة لا يستبعده.

طالما أن النتيجة النهائية هي ذلك difference لديه القيمة 2, ، معيار اللغة لا يهتم بكيفية القيام بذلك.

ومن ناحية أخرى، إذا كتبت:

switch (foo) {
    case 5 - 3: /* ... */
    case 2:     /* ... */
}

ثم المترجم يجب احسب النتيجة حتى تتمكن من تشخيص الخطأ (لا يمكن أن يكون لديك تصنيفان لحالة بنفس القيمة.

وأخيرا، إذا قمت بتحديد difference في نطاق الملف (خارج أي وظيفة)، ثم القيمة الأولية يفعل يجب أن تكون ثابتة.لكن التمييز الحقيقي في هذه الحالة ليس ما إذا كان الأمر كذلك أم لا 5 - 3 سيتم تقييمه في وقت الترجمة، فهو ما إذا كنت مسموح لاستخدام تعبير غير ثابت.

مرجع:أحدث مسودة لمعيار 2011 C هي N1570 (ملف PDF كبير)؛تمت مناقشة التعبيرات الثابتة في القسم 6.6.

نصائح أخرى

المعيار لا يحدد هذا النوع من الأشياء.لا يذكر شيئًا عن التحسينات المحتملة مثل هذا (ولسبب وجيه.المعيار يحدد الدلالات، وليس التنفيذ).

لماذا لا تنظر إلى التفكيك للمترجم الخاص بك؟سيعطيك ذلك إجابة محددة.

...

لذلك دعونا نفعل ذلك.

هنا هو الإخراج من VC++ 10:

#include <iostream>

#define A 5
#define B 3

int main() {
    int x = A - B;
    std::cout << x;  // make sure the compiler doesn't toss it away
010A1000  mov         ecx,dword ptr [__imp_std::cout (10A2048h)]  
010A1006  push        2  
010A1008  call        dword ptr [__imp_std::basic_ostream<char,std::char_traits<char> >::operator<< (10A2044h)]  
    return 0;
010A100E  xor         eax,eax  

كما ترون، فإنه مجرد استبدال حدوث x بقيمة ثابتة تبلغ 2 ودفعتها إلى المكدس للاتصال بـ cout.لم يتم تقييم التعبير في وقت التشغيل.

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