C / C ++: как использовать do-while (0); построить без предупреждения компилятора, как C4127? - PullRequest
43 голосов
/ 22 декабря 2009

Я часто использую конструкцию do-while (0) в моих #defines по причинам, описанным в этом ответе . Также я пытаюсь использовать как можно более высокий уровень предупреждения от компилятора, чтобы уловить больше потенциальных проблем и сделать мой код более надежным и кроссплатформенным. Поэтому я обычно использую -Wall с gcc и /Wall с MSVC.

К сожалению, MSVC жалуется на конструкцию do-while (0):

foo.c(36) : warning C4127: conditional expression is constant

Что мне делать с этим предупреждением?

Просто отключить это глобально для всех файлов? Мне кажется, это не очень хорошая идея.

Ответы [ 20 ]

1 голос
/ 07 октября 2013

Вы можете использовать оператор запятой вместо конструкции do-while (0) для макроса с несколькими утверждениями, который будет использоваться в выражениях. Так что вместо:

#define FOO(...)    do { Statement1; Statement2; Statement3; } while(0)

Использование:

#define FOO(...)    (Statement1, Statement2, Statement3)

Это работает независимо от платформы и позволяет избежать предупреждения компилятора (даже если выбран самый высокий уровень предупреждения). Обратите внимание, что в макросе, содержащем запятую (второе FOO), результат последнего оператора (Statement3) будет результатом всего макроса.

1 голос
/ 22 декабря 2009

Этот материал "while (0)" взломан и только что развернулся, чтобы укусить вас.

Предлагает ли ваш компилятор #pragma с для выборочного и локального отключения определенных сообщений об ошибках? Если это так, это может быть разумной альтернативой.

0 голосов
/ 04 октября 2016

Вы можете использовать for цикл как:

for (;;) {
  // code
  break;
}

Macro:

#define BEGIN \
  for (;;) {

#define END \
  break; }
0 голосов
/ 22 декабря 2009

Решение есть, но оно добавит больше циклов в ваш код. Не используйте явное значение в условии while.

Вы можете сделать это так:

file1.h

extern const int I_am_a_zero;
#define MY_MACRO(foo,bar) \
do \
{ \
} \
while(I_am_a_zero);

переменная I_am_a_zero должна быть определена в каком-то файле .c.

В любом случае это предупреждение не отображается в GCC:)

Смотрите этот связанный вопрос .

0 голосов
/ 22 декабря 2009

Вы можете использовать #pragma предупреждение для:

  1. сохранить состояние
  2. отключить предупреждение
  3. написать обидный код
  4. вернуть предупреждение в прежнее состояние

(вам нужен знак # перед прагмами, но SO с трудом справляется с ними и одновременно форматирует)

#pragma warning( push )
#pragma warning( disable: 4127 )
// Your code
#pragma warning( pop ) 

Вы хотите нажимать / выдвигать предупреждения, а не отключать / включать, потому что вы не хотите вмешиваться в аргументы командной строки, которые могут быть выбраны для включения / выключения предупреждений (кто-то может использовать командную строку, чтобы отключить предупреждение , вы не хотите принудительно возвращать его ... код выше имеет дело с этим).

Это лучше, чем глобальное отключение предупреждения, поскольку вы можете управлять им только для той части, которую хотите. Также вы можете сделать его частью макроса.

0 голосов
/ 19 октября 2012

Я бы использовал

for(int i = 0; i < 1; ++i) //do once
{

}

Это эквивалентно

do
{
}while(0);

и не выдает предупреждений.

0 голосов
/ 09 февраля 2016

Я нашел, что это самая короткая версия

do {
  // ... 
}
while (([]() { return 0; })())  /* workaround for MSVC warning C4172 : conditional expression is constant */

Не проверил, оптимизировал ли он компилятор, но я бы предположил, что это так.

0 голосов
/ 20 декабря 2015

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

static inline bool to_bool(const bool v) { return v; }

if (to_bool(0)) { // no warning here
    dead_code(); // will be compiled out (by most compilers)
}

do { something(); } while(to_bool(0)); // no extra code generated
0 голосов
/ 13 августа 2015

Ну, для меня работает следующее без предупреждения C4127:

#define ALWAYS_TRUE(zzsome) ((##zzsome)==(##zzsome))

void foo()
{
    int a = 0;
    while( ALWAYS_TRUE(a) )
    {
    }
}

Конечно, компиляторы умны и zzsome не должен быть константой

0 голосов
/ 22 декабря 2009

Должен сказать, я никогда не задумывался о конструкции do.. while в макросах. Весь код в моих макросах сам по себе включен в фигурные скобки, но без do - .. while. Например:

#define F(x) \
    {           \
        x++;    \
    }           \

int main() {
    int a = 1;
    F(a);
    printf( "%d\n", a );
}

Кроме того, мой собственный стандарт кодирования (и неформальная практика в течение многих лет) заключался в том, чтобы все блоки, где бы они ни происходили, заключались в фигурные скобки, что также более или менее устраняет проблему.

...