Как работает расширение макроса C? - PullRequest
0 голосов
/ 26 февраля 2012

позвольте мне объяснить мою путаницу с примером кода

это наш макрос

#define rsAssert(v)   if(!(v)) printf("rsAssert failed: %s, in %s at %i" #v, __FILE__, __LINE__); 

case 1:

int main(void)
{
  rsAssert(0);
  return 0;
}

this caseкомпилируется успешно

case 2

int main(void)
{
  rsAssert(0)  // note here ;  is not present
  return 0;
}

также компилируется успешно Вопрос 1:

это означает, что вы пишете rsAssert(0) или rsAssert(0); нет разницы между ними?


тогда

дело 3

int main()
{
  if(1)
    rsAssert(0);
  else 
    printf("mr.32");
  return 0;
}

здесь rsassert(0); нетсобираюсь скомпилировать [см. http://ideone.com/7dFv1] , но без ; rsasser(0) отлично работает [см. http://ideone.com/8fehl]..

Я не понимаю, что происходит с расширением макроса здесь ...

Ответы [ 4 ]

4 голосов
/ 26 февраля 2012

Это самая главная причина, по которой я всегда заставляю своих программистов использовать тела для всех своих операторов if.

int main()
{
  if (1)
    if(!(0))
      printf("rsAssert failed: %s, in %s at %i", "0", __FILE__, __LINE__);
    else 
      printf("mr.32");
  return 0;
}

предотвращено хорошими стандартами кодирования

int main()
{
  if (1){
    if(!(0)){
      printf("rsAssert failed: %s, in %s at %i", "0", __FILE__, __LINE__);
      }
    }
    else {
      printf("mr.32");
    }
  return 0;
}

Исправления низкой стоимости изменения перечисленного удара.

#define rsAssert(v) (printf( (!v)?"rsAssert failed: %s, in %s at %i":"", #v, __FILE__, __LINE__))

Это будет работать, но всегда будет printf.

#define rsAssert(v) ((!v)?printf("rsAssert failed: %s, in %s at %i", #v, __FILE__, __LINE__):0)

Это будет распечатано, только если вы отключите утверждение, но выглядит грязно

Также учтите следующее!

if( rand()%2 )
  FooLog("Hello World");
ImportantFunction();

#if DEBUG
#define FooLog printf
#else
#define FooLog //
#endif

В выпуске важная функция работает 100% времени, 50% времени.

4 голосов
/ 26 февраля 2012

Причина, по которой он не работает в случае 3, заключается в том, что это то, что на самом деле компилируется:

int main()
{
if(1)
  if(!(v)) printf("rsAssert failed: %s, in %s at %i", #v, __FILE__, __LINE__);;
else 
  printf("mr.32");
return 0;
}

Обратите внимание на лишнюю точку с запятой в конце первого printf из макроса.

Обычно с оператором if следует один оператор или блок с {}.

Но из-за дополнительного; у вас есть это:

if (...) 
    printf(...); ;
else
    printf(...);
return 0;

Эта лишняя точка с запятой - пустое утверждение, но, тем не менее, это утверждение.

Вы должны удалить; из макроса. Тогда все станет более разумным.

2 голосов
/ 26 февраля 2012

Я полагаю, что в случае 3 он вообще не работает. Выполните расширение вручную (и сделайте для него отступ, чтобы оно имело смысл):

int main()
{
  if (1)
    if(!(0))
      printf("rsAssert failed: %s, in %s at %i", "0", __FILE__, __LINE__);
    else 
      printf("mr.32");
  return 0;
}

Как видите, else заканчивается неправильным оператором if. Если вы хотите, чтобы работал макрос, содержащий оператор if, вам нужно, чтобы он выглядел как простой оператор. Упаковка в do... while(0) идиоматична:

#define rsAssert(v)                                                         \
    do {                                                                    \
      if(!(v))                                                              \
        printf("rsAssert failed: %s, in %s at %i", #v, __FILE__, __LINE__); \
    } while (0) 
1 голос
/ 26 февраля 2012
if(1)
  rsAssert(0); // Original semicolon
else 
  ....

расширяется до

if(1)
   if(!(v)) printf("rsAssert failed: %s, in %s at %i",
       #v, __FILE__, __LINE__);; // Notice the extra semicolon. The extra from the
                                 // macro expansion.
else
    ....

Эта лишняя точка с запятой вызывает новый пустой оператор. Поскольку {} не существует, для оператора if, else не следует сразу же, и это то, на что жалуется компилятор. Итак, делай -

if(1)
{
  rsAssert(0);
}
 else 
  ....
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...