c ترجمة - ما فائدة القيام به أثناء(0)عندما نحدد الماكرو؟




العربية بالانجليزي (3)

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

بدون الوقت (0) ، لن يعمل كودك أعلاه

if (doit) 
   INIT_LIST_HEAD(x);
 else 
   displayError(x);

بما أن الفاصلة المنقوطة بعد الماكرو "ستأكل" عبارة "آخر" ، وما سبق لن يتم تجميعها.

ممكن تكرار:
Do-While وبيانات if-else في وحدات الماكرو C / C ++

أنا أقرأ نواة لينكس ولقد وجدت العديد من وحدات الماكرو مثل هذا:

#define INIT_LIST_HEAD(ptr) do { \
    (ptr)->next = (ptr); (ptr)->prev = (ptr); \
} while (0)

لماذا يستخدمونها بدلاً من تعريفها ببساطة في {}؟


يسمح لك بتجميع عدة عبارات في ماكرو واحد.

افترض أنك فعلت شيئًا مثل:

if (foo) 
    INIT_LIST_HEAD(bar);

إذا تم تعريف الماكرو بدون تغليف {...} أثناء (0) ؛ ، سيتم توسيع التعليمة البرمجية أعلاه إلى

if (foo)
    (bar)->next = (bar);
    (bar)->prev = (bar);

من الواضح أن هذا لم يكن المقصود ، حيث سيتم تنفيذ البيان الأول فقط إذا كان يحمل فو. سيتم تنفيذ البيان الثاني بغض النظر عما إذا كان يحمل foo.

تعديل: مزيد من الشرح على http://c-faq.com/cpp/multistmt.html و http://developer.apple.com/documentation/DeveloperTools/gcc-4.0.1/cpp/Swallowing-the-Semicolon.html#Swallowing-the-Semicolon


http://bytes.com/groups/c/219859-do-while-0-macro-substitutions

أندريه تاراسيفيتش:

إن الفكرة الكاملة لاستخدام إصدار 'do / while' هي جعل الماكرو الذي سيتوسع إلى بيان عادي ، وليس في جملة مركبة. ويتم ذلك من أجل جعل استخدام وحدات الماكرو على غرار الوظيفة موحدة مع استخدام الوظائف العادية في جميع السياقات.

النظر في التعليمات البرمجية التالية

if (<condition>)
  foo(a);
else
  bar(a);

حيث "foo" و "bar" هي وظائف عادية. الآن تخيل أنك تريد استبدال الوظيفة "foo" باستخدام ماكرو من الطبيعة المذكورة أعلاه

if (<condition>)
  CALL_FUNCS(a);
else
  bar(a);

الآن ، إذا تم تعريف الماكرو الخاص بك وفقًا للنهج الثاني (فقط '{' و '}') لن يتم ترجمة الشفرة ، نظرًا لأن الفرع 'الحقيقي' من 'if' يتم تمثيله الآن بواسطة عبارة مركبة. وعندما تضع "؛" بعد هذا البيان المركب ، انتهيت من العبارة "if" بأكملها ، وبالتالي عزل فرع "آخر" (ومن هنا جاء خطأ الترجمة).

إحدى طرق تصحيح هذه المشكلة هي تذكر عدم وضع "؛" بعد ماكرو "دعوات"

if (<condition>)
  CALL_FUNCS(a)
else
  bar(a);

سيعمل هذا على ترجمة والعمل على النحو المتوقع ، ولكن هذا ليس موحدًا. الحل الأكثر أناقة هو التأكد من أن الماكرو يتوسع في بيان عادي ، وليس في واحد مركب. إحدى الطرق لتحقيق ذلك هي تعريف الماكرو كما يلي

#define CALL_FUNCS(x) \
do { \
  func1(x); \
  func2(x); \
  func3(x); \
} while (0)

الآن هذا الرمز

if (<condition>)
  CALL_FUNCS(a);
else
  bar(a);

سوف تترجم دون أي مشاكل.

ومع ذلك ، لاحظ الفرق صغير ولكن مهم بين التعريف الخاص بي CALL_FUNCS والإصدار الأول في رسالتك. لم أضع بعد } while (0) . وضع في نهاية هذا التعريف من شأنه أن يهزم على الفور نقطة كاملة من استخدام 'القيام به / أثناء' وجعل هذا الماكرو يعادل إلى حد كبير إصدار مجمع البيان.

لا أعرف سبب وضع مؤلف الشفرة التي اقتبستها في رسالتك الأصلية هذا ; بعد while (0) . في هذا الشكل كلا المتغيرين متساويين. الفكرة الكاملة وراء استخدام إصدار 'do / while' لا تشمل هذا النهائي ; في الماكرو (للأسباب التي شرحتها أعلاه).





c macros linux-kernel