2015-03-11 3 views
16

Ответ на вопрос this, я предложил использовать do {...} while(0) для многострочных макросов.является `предупреждение C4127` (условное выражение постоянное) когда-либо полезно?

На MSVC, я нашел этот код подбрасывает:

warning C4127: conditional expression is constant 

Чтобы сделать код предупреждения бесплатно, мне нужно выбрать одну из этих уродливых альтернатив:

Вариант 1

#ifdef _MSC_VER 
#pragma warning(push) 
#pragma warning(disable:4127) 
#endif 
code_using_macro_that_generates_C4217; 
#ifdef _MSC_VER 
#pragma warning(pop) 
#endif 

Вариант 2
Определить мои макросы:

#define MULTI_LINE_MACRO do { ... } while(0,0) 

или

#define MULTI_LINE_MACRO do { ... } while((void)0,0) 

называют также "сова" некоторыми программистами, как (0,0) выглядит как сова.

Вариант 3
Определить новый макрос WHILE_0, который не генерирует предупреждение и использовать его вместо while(0)

Проблемы
Я считаю, что все альтернативы более или менее ужасно. Почему MSVC генерирует это предупреждение для кажущегося правильного кода и мотивирует меня добавить некоторое уродство к моему коду, чтобы оставить код предупреждения свободным?

Я считаю, что постоянные выражения в условных выражениях являются вполне допустимыми и полезными, в частности, в конструкциях, основанных на способности компилятора оптимизировать код.

Кроме того, я не получаю warning C4127 для кода, как это:

void foo(unsigned bar) 
{ 
    while (bar >= 0) 
     ; 
} 

Мой вопрос: Не warning C4127: conditional expression is constant полностью бесполезный и делает это не мотивируют уродливый код? Предупреждает ли это предупреждение о написании лучшего кода?

+8

@Bathsheba: but 'for (;;)' не имеет то же значение, что 'do {' ... '} while (0)' !!!! –

+1

Ну, если MSVC поддерживает C11 (*, который он не делает), тогда предупреждение не имеет большого смысла, поскольку у C11 есть конкретное исключение для [постоянных выражений в качестве управляющего выражения для предотвращения оптимизации бесконечных циклов] (http: // stackoverflow.com/a/28681034/1708801) Я понимаю, что это противоположный случай, но по-прежнему применяется. –

+6

Удалите 'pragma' и [#include" no_sillywarnings_please.h "] (https://alfps.wordpress.com/the-no_sillywarnings_please-h-file/) –

ответ

5

Я не думаю, что это когда-либо полезно. Напротив, есть больше ложных срабатываний, чем только идиома do .. while(0). Подумайте конструктов как

if(sizeof(long) == 8) { /* ... */ } 
if(SOME_CONSTANT_MACRO) { /* ... */ } 

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

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

Из приведенных ниже примеров (у меня не было MSVC для тестирования самостоятельно), похоже, что предупреждение предназначено для постоянных выражений в смысле языка C (то есть не то, что может быть постоянным сложенное, но синтаксически не является постоянным выражением), поэтому он не испускается для if(array) или if(function) (что, например, gcc -Wall, предупреждает об этом, поскольку он, вероятно, предназначен для вызова функции).

while(0,0) хуже, на мой взгляд, оно вызывает предупреждение с gcc -Wall для левой стороны оператора запятой без побочных эффектов, предупреждение, которое я могу себе представить, что иногда полезно (и который обычно легко избежать). Это предупреждение исчезает с while((void)0,0).

Предлагаю отключить предупреждение.

3

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

Например, если вы пишете что-то вроде:

if (x != NULL) { /* ... */ } 

где x является объектом массива, то выражение справедливо, но выражение x распадается на указатель на начальный элемент массива, который не может быть нулевым указателем. Я не знаю, вызывает ли та же ошибка, но это пример того же самого.

Конечно, это не всегда полезно.В вашем случае,

do { /* ... */ } while (0) 

идиом это лучший способ, чтобы написать определение макроса, который предназначен для использования в контексте, который требует заявлений. Использование while (0) в другом контексте скорее всего будет логической ошибкой [*].

К сожалению, ваш компилятор не признает его распространенной идиомой. Создание хороших предупреждений сложно. компилятор должен выйти за рамки правил языка и сделать вывод о намерении программиста.

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

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

[*] Если вы хотите использовать break, можно сделать вывод, что вы можете выскочить из него.

+3

Из приведенных примеров, похоже, срабатывает предупреждение только для постоянных выражений (не для непостоянных конструкций, которые могут быть сложенными по константам), поэтому он не испускается для 'if (x! = NULL)'. В противном случае, почему это не срабатывает для 'if (0,0)'? – mafso

 Смежные вопросы

  • Нет связанных вопросов^_^