C ماكرو متعدد الأسطر:افعل/أثناء (0) مقابل كتلة النطاق [مكررة]

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

  •  21-08-2019
  •  | 
  •  

سؤال

التكرارات المحتملة:
ما فائدة do while(0) عندما نحدد ماكرو؟
لماذا توجد في بعض الأحيان عبارات do/while وif/else لا معنى لها في وحدات الماكرو C/C++؟
افعل { … } بينما (0) ما فائدة ذلك؟

لقد رأيت بعض وحدات ماكرو C متعددة الأسطر ملفوفة داخل حلقة do/while(0) مثل:

#define FOO \
  do { \
    do_stuff_here \
    do_more_stuff \
  } while (0)

ما هي فوائد (إن وجدت) لكتابة الكود بهذه الطريقة بدلاً من استخدام الكتلة الأساسية:

#define FOO \
  { \
    do_stuff_here \
    do_more_stuff \
  }
هل كانت مفيدة؟

المحلول

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

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

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

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

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

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

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

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

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

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).وضع أ ; في نهاية هذا التعريف ، سيهزم على الفور نقطة استخدام "do/year" وجعل هذا الماكرو يعادل إلى حد كبير إصدار المجموعة المركبة.

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

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