Это безопасное определение препроцессора C без скобок?
В моем каталоге /usr/include
существует как минимум два варианта #define NULL 0
, предназначенных для кода С++ 1:
#define NULL 0 // from rpc/types.h
#define NULL (0) // from libio.h
Я чувствую, что должен быть встречный пример, где первый не был бы безопасным, но я не смог его создать.
В противном случае есть ли веские аргументы в пользу того, почему в этом случае было бы безопасно не включать круглые скобки (например, неформальное "доказательство правильности" )?
1 То есть без включения варианта #define NULL ((void*)0)
, который полезен для C, но недействителен в С++.
Ответы
Ответ 1
Нет никакой разницы. Единственными операторами с более высоким приоритетом являются ::
, ++
и --
, и они не применимы в 0
и (0)
.
Единственное смешное различие, которое я вижу, - обфускация:
#define NULL (0)
void f(int x)
{
// Do something with x
}
int main()
{
f NULL; // This code compiles
return 0;
}
Ответ 2
Я считаю, что последнее могло возникнуть из-за обработки грузов, т.е. правило/рефлекс, чтобы всегда правильно определять препроцессоры в круглых скобках.
Ответ 3
Если мы говорим о безопасности, можно утверждать, что #define NULL 0
на самом деле безопаснее, чем #define NULL (0)
.
Вы видите, последний позволяет вам сделать что-то вроде этого: a = func NULL;
вместо a = func(0);
, который может создать неконтролируемую ядерную реакцию в мозге любого, кто видит это в коде C производства. Это совершенно небезопасно, вы знаете =)
Ответ 4
Так как никто еще не ясно изложил это...
есть ли какой-то веский аргумент о том, почему в этом случае было бы безопасно не включать круглые скобки (например, неформальное "доказательство правильности" )?
Скобки представляют собой группирующую конструкцию. Они принимают выражение и превращают его в первичное выражение (использовать имена из стандартной грамматики). Полное первичное выражение не может быть "достигнуто" и разделено оператором, применяемым к нему, независимо от этого приоритета оператора. Помимо вопроса, упомянутого в комментариях с вызовами функций и if
, это все, что они делают; они используются в макросах, чтобы гарантировать, что расширенный результат имеет тот же приоритет, что и у него в источнике (константа выглядит как атом, первичное выражение обрабатывается так же, как и в структуре выражения).
Цифра 0
является синтаксическим атомом. Он уже определен как первичное выражение из-за того, что он является литеральной константой. Внутренняя структура выражения для оператора не разделяется, и вопрос о приоритете даже не применяется. Так как для скобок не существует приоритета для изменения, их перенос в них преобразует первичное выражение в другое первичное выражение, т.е. Оно буквально ничего не делает.
Ссылка: C11 6.5.1 "Первичные выражения" , С++ 11 5.1.1 "Первичные выражения" .
Ответ 5
Это безопасно, по крайней мере, без каких-либо неожиданных последствий приоритета оператора.
Любое определение макроса, которое является простым литералом без каких-либо операторов, всегда безопасно. например,...
#define FOO 1
#define NAME "Fred"
#define malloc my_malloc