Подтвердить что ты не робот

Это безопасное определение препроцессора 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, но недействителен в С++.

4b9b3361

Ответ 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