Зачем использовать явно бессмысленные операторы do-while и if-else в макросах?

Макросы — это копируемые/вставляемые c++ фрагменты текста, которые c++ препроцессор вставляет в c++-faq подлинный код; автор макроса c++ надеется, что замена даст c++-faq корректный код.

Есть три хороших c++-faq «совета», чтобы преуспеть c++-faq в этом:

Помогите макросу вести себя как настоящий код

Обычный код обычно cpp заканчивается точкой с запятой. Если cpp код просмотра пользователя cxx не нужен...

doSomething(1) ;
DO_SOMETHING_ELSE(2)  // <== Hey? What's this?
doSomethingElseAgain(3) ;

Это означает, что cpp пользователь ожидает, что c-preprocessor компилятор выдаст ошибку, если c++-faq точка с запятой отсутствует.

Но cpp на самом деле действительно c++-faq хорошая причина заключается c-preprocessor в том, что в какой-то момент c++ автору макроса, возможно, потребуется c-preprocessor заменить макрос подлинной cxx функцией (возможно, встроенной). Так cpp что макрос должен действительно вести c++ себя как один.

Итак, у нас c++ должен быть макрос, которому c++-faq нужна точка с запятой.

Создайте действительный код

Как c++ показано в ответе jfm3, иногда c++ макрос содержит более одной cxx инструкции. И если макрос c++ используется внутри оператора cxx if, это будет проблематично:

if(bIsOk)
   MY_MACRO(42) ;

Этот c макрос можно расширить следующим c++ образом:

#define MY_MACRO(x) f(x) ; g(x)

if(bIsOk)
   f(42) ; g(42) ; // was MY_MACRO(42) ;

Функция g будет выполняться c++ независимо от значения bIsOk.

Это c-preprocessor означает, что мы должны добавить c область макроса:

#define MY_MACRO(x) { f(x) ; g(x) ; }

if(bIsOk)
   { f(42) ; g(42) ; } ; // was MY_MACRO(42) ;

Создать действительный код 2

Если макрос c-preprocessor примерно такой:

#define MY_MACRO(x) int i = x + 1 ; f(i) ;

У нас может c-preprocessor быть другая проблема в следующем cxx коде:

void doSomething()
{
    int i = 25 ;
    MY_MACRO(32) ;
}

Потому что это расширится c как:

void doSomething()
{
    int i = 25 ;
    int i = 32 + 1 ; f(i) ; ; // was MY_MACRO(32) ;
}

Этот код, конечно же, не c++ скомпилируется. Итак, опять cxx же, решение использует область c++ видимости:

#define MY_MACRO(x) { int i = x + 1 ; f(i) ; }

void doSomething()
{
    int i = 25 ;
    { int i = 32 + 1 ; f(i) ; } ; // was MY_MACRO(32) ;
}

Код снова работает cpp корректно.

Комбинировать эффекты точки с запятой и области видимости?

Есть одна идиома c++-faq C/C++, которая производит c++-faq этот эффект: Цикл do/while:

do
{
    // code
}
while(false) ;

do/while cxx может создать область действия, таким c образом инкапсулируя код c++-faq макроса, и нуждается в точке c с запятой в конце, таким cxx образом расширяясь в код, нуждающийся c-preprocessor в ней.

Бонус?

Компилятор C++ оптимизирует cxx цикл do/while, поскольку cxx тот факт, что его постусловие c++-faq ложно, становится известен c++-faq во время компиляции. Это cpp означает, что макрос вида:

#define MY_MACRO(x)                                  \
do                                                   \
{                                                    \
    const int i = x + 1 ;                            \
    f(i) ; g(i) ;                                    \
}                                                    \
while(false)

void doSomething(bool bIsOk)
{
   int i = 25 ;

   if(bIsOk)
      MY_MACRO(42) ;

   // Etc.
}

будет c правильно расширяться как

void doSomething(bool bIsOk)
{
   int i = 25 ;

   if(bIsOk)
      do
      {
         const int i = 42 + 1 ; // was MY_MACRO(42) ;
         f(i) ; g(i) ;
      }
      while(false) ;

   // Etc.
}

, а c++-faq затем компилируется и оптимизируется c++ как

void doSomething(bool bIsOk)
{
   int i = 25 ;

   if(bIsOk)
   {
      f(43) ; g(43) ;
   }

   // Etc.
}

c++

c

c-preprocessor

c++-faq

2022-11-08T12:30:25+00:00
Вопросы с похожей тематикой, как у вопроса:

Зачем использовать явно бессмысленные операторы do-while и if-else в макросах?