هل تعلق شريط Preprocessor C أو توسيع وحدات الماكرو أولا؟ [مكرر

StackOverflow https://stackoverflow.com/questions/1510869

سؤال

هذا السؤال لديه بالفعل إجابة هنا:

النظر في هذا (فظيع، فظيع، لا جيد، سيئة للغاية) هيكل رمز:

#define foo(x) // commented out debugging code

// Misformatted to not obscure the point
if (a)
foo(a);
bar(a);

لقد رأيت اثنين من المترجمين قبل أن تولد نتائج مختلفة على هذا الرمز:

if (a)
bar(a);

و

if (a)
;
bar(a);

من الواضح أن هذا شيء سيء لقاعدة رمز محمول.

سؤالي: ما هو Preprocessor من المفترض أن يفعل ذلك بهذا؟ Elide تعليقات أولا، أو قم بتوسيع وحدات الماكرو أولا؟

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

المحلول

لسوء الحظ، الأصلي ANSI C المواصفات باستثناء خصيصا أي ميزات Preprocessor في القسم 4 ("توضح هذه المواصفات لغة C فقط. لا يوجد أي اعتماد إما للمكتبة أو Preprocessor.").

ال مواصفات C99. يعالج هذا السليل، رغم ذلك. يتم استبدال التعليقات بمساحة واحدة في "مرحلة الترجمة"، والتي تحدث قبل تحليل التوجيه المعالج مسبقا. (القسم 6.10 للحصول على التفاصيل).

VC ++. و ال مترجم جنو ج كلاهما يتبع هذا النموذج - قد لا يكون المغلوانات الأخرى متوافقة إذا كانوا أكبر سنا، ولكن إذا كان ذلك متوافقا مع C99، يجب أن تكون آمنا.

نصائح أخرى

كما هو موضح في هذه النسخة التي تم لصقها من مراحل الترجمة في معيار C99، إزالة التعليقات (يتم استبدالها بمسافة بيضاء واحدة) تحدث في المرحلة الثالثة من الترجمة 3، في حين يتم معالجة توجيهات معالجة مسبقا ويتم توسيع وحدات الماكرو في المرحلة 4.

في معيار C90 (الذي لدي فقط في نسخة صلبة، لذلك لا توجد نسخ نسخ - معجون) تحدث هاتين المرحلتين بنفس الترتيب، على الرغم من أن وصف مراحل الترجمة يختلف قليلا في بعض التفاصيل من معيار C99 - الحقيقة تتم إزالة التعليقات واستبدالها بحرف مبيعا واحدا قبل التعامل مع توجيهات مسبقة مسبقا ومعاد الماكرات الموسعة ليست مختلفة.

مرة أخرى، تحتوي معيار C ++ على هذه المراحل 2 تحدث بنفس الترتيب.

بقدر ما هو "//يجب معالجة التعليقات، وتقول معيار C99 هذا (6.4.9 / 2):

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

وتقول معيار C ++ (2.7):

الشخصيات // بدء تعليق، والذي ينتهي بالحرف الجديد التالي.

لذلك يمثل المثال الأول خطأ في جزء من هذا المترجم -;"شخصية بعد foo(a) يجب الاحتفاظ بها عندما foo() يتم توسيع الماكرو - يجب ألا تكون أحرف التعليق جزءا من "محتويات" the foo() دقيق.

ولكن نظرا لأنك تواجه مترجم عربات التي تجرها الدواب، فقد ترغب في تغيير تعريف الماكرو إلى:

#define foo(x) /* junk */

لتحمل الخطأ.

ومع ذلك (وأنا تنجرف عن الموضوع هنا ...)، لأن خط الربط (خطوط الخلفية فقط قبل خط جديد) يحدث قبل معالجة التعليقات، يمكنك تشغيل شيء مثل هذا القليل من الرمز السيء:

#define evil( x) printf( "hello "); // hi there, \
                 printf( "%s\n", x); // you!



int main( int argc, char** argv)
{
    evil( "bastard");

    return 0;
}

والتي قد مفاجأة من كتبها.

أو حتى أفضل، جرب ما يلي، كتبه شخص ما (بالتأكيد ليس لي!) الذي يحب تعليقات على غرار المربع:

int main( int argc, char** argv)
{
                            //----------------/
    printf( "hello ");      // Hey, what the??/
    printf( "%s\n", "you"); // heck??         /
                            //----------------/
    return 0;
}

اعتمادا على ما إذا كان برنامج التحويل البرمجي الافتراضي للمعالجة المهاجرات المهيورة أم لا (من المفترض أن مفاجأة التحويل البرمجيات، ولكن نظرا لأن المخاضعات مفاجأة تقريبا كل من يدير عبرها، يقرر بعض المترجمين تشغيلها بشكل افتراضي)، قد تحصل أو لا تحصل على السلوك الذي تريده - مهما كان السلوك، بالطبع.

وفق MSDN., ، يتم استبدال التعليقات بمساحة واحدة في مرحلة التكييف، والتي تحدث قبل مرحلة المعالجة المسبقة حيث يتم توسيع وحدات الماكرو.

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

#define foo(x) do { } while(0) /* junk */

بهذه الطريقة، فو دائما آمنة للاستخدام. علي سبيل المثال:

if (some condition)
    foo(x);

لن يتم إلقاء خطأ مترجم بغض النظر عن ما إذا كان يتم تعريف فو أم لا إلى بعض التعبير.

#ifdef _TEST_
#define _cerr cerr
#else
#define _cerr / ## / cerr
#endif
  • سوف تعمل على بعض المحاصيل (VC ++). متي _TEST_ غير محدد،

    _cerr ...

    سيتم استبداله بموجب خط التعليق

    // cerr ...

يبدو أنني أتذكر أن الامتثال يتطلب ثلاث خطوات:

  1. قطاع
  2. توسيع وحدات الماكرو
  3. الشريط مرة أخرى

سبب هذا له علاقة بالمترجم القادر على قبول .i الملفات مباشرة.

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