В макросах C, следует ли предпочесть {...} while (0,0) over do {...} while (0)?

Недавно клиент выполнил статический анализ кода моего работодателя C и дал нам результаты. Среди полезных исправлений был запрос на изменение знаменитого макроса do { ... } while(0) до do { ... } while(0,0). Я понимаю, что делает их патч (использование оператора последовательности для return оценивает значение второго "0", поэтому эффект тот же), но неясно, почему они предпочитают второй формы над первой формой.

Есть ли законная причина, почему нужно предпочесть вторую форму макроса, или наш статический анализ наших клиентов является слишком педантичным?

Ответ 1

Хорошо, я отвечу на вопрос:

Есть ли законная причина, почему нужно предпочесть вторую форму макроса...?

Нет. Нет законной причины. Оба всегда оцениваются как false, и любой достойный компилятор, вероятно, превратит второй в первый в сборке. Если в некоторых случаях была какая-то причина для его недействительности, C был достаточно длинным, чтобы по этой причине были открыты более гуру, чем я.

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

Ответ 2

Просто угадайте, почему они могут предложить использовать

do { ... } while(0,0)

над

do { ... } while(0)

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

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

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

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

assert( !"We should have never gotten here, dammit...");

Но, по крайней мере, один компилятор я использую проблемы, предупреждая о том, что выражение всегда оценивает значение false. Однако, если я изменю его на:

assert( ("We should have never gotten here, dammit...", 0));

Предупреждение уходит, и все счастливы. Я предполагаю, что даже ваш инструмент статического анализа ваших клиентов тоже будет. Обратите внимание, что я обычно скрываю этот кусок обруча, прыгающий за макросом вроде:

#define ASSERT_FAIL( x) assert( ((x), 0))

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

Ответ 3

Использование while (0,0) не позволяет компилятору Microsoft генерировать предупреждение о состоянии, которое является константой (Warning C4127).

Когда это предупреждение включено (например, с /W 4 или/Wall), его можно отключить в каждом конкретном случае с помощью этого приятного маленького трюка (см. этот другой поток).