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

Есть ли веская причина всегда включать определение в круглые скобки в C?

Очевидно, что в некоторых случаях операторы #define должны иметь круглые скобки, например:

#define WIDTH 80+20

int a = WIDTH * 2; // expect a==200 but a==120

Поэтому я всегда заключаю в скобки, даже когда это просто одно число:

#define WIDTH (100)

Кто-то новичок в C спросил меня, почему я это делаю, поэтому я попытался найти крайний случай, когда отсутствие круглых скобок для одного числа #define вызывает проблемы, но я не могу придумать ни одного.

Существует ли такой случай?

4b9b3361

Ответ 1

Да. Оператор конкатенации препроцессора (##) вызовет проблемы, например:

#define _add_penguin(a) penguin ## a
#define add_penguin(a) _add_penguin(a)

#define WIDTH (100)
#define HEIGHT 200    

add_penguin(HEIGHT) // expands to penguin200
add_penguin(WIDTH)  // error, cannot concatenate penguin and (100) 

То же самое для строкования (#). Ясно, что это угловой случай и, вероятно, не имеет значения, учитывая, что WIDTH предположительно будет использоваться. Тем не менее, это то, что нужно помнить о препроцессоре.

(Причина, по которой сбой второго пингвина не получается, - это тонкая деталь правил предварительной обработки в C99 - iirc это не удается, потому что объединение двух токенов предварительной обработки не должно заполнить обязательный токен, который должен иметь единственный токен предварительной обработки, но это не имеет значения, даже если бы конкатенация была разрешена, она все равно дала бы другой результат, чем неустановленный #define!).

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

Ответ 2

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

Прямо сейчас ваш макрос представляет собой одно целое число. Вообразите, что кто-то редактирует это в будущем. Допустим, они не вы, а тот, кто менее осторожен или более спешит. Скобки предназначены для напоминания людям о внесении каких-либо изменений в них.

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

Ответ 3

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

Ответ 4

Как Благовест Буюклиев сказал:

Определение состоит из одного токена (только один операнд, без операторов), скобки не нужны, потому что один токен (например, 100) является неделимым атомом при лексинге и разборе.

Но я бы рекомендовал следующие правила, когда дело доходит до макросов:

  • Избегайте таких функций, как макросы @see Lundin comment.

Если вы хотите использовать функцию вроде макросов, плохо рассмотрите следующие 2 правила:

  • Всегда используйте скобки для аргументов в макросах
  • Использовать только аргумент макроса

Зачем нужно правило 1.? (Чтобы сохранить порядок операций правильно)

#define quad(x) (x*x)
int a = quad(2+3);

будет расширяться до:

int a = (2+3*2+3);

Почему правило 2.? (Чтобы гарантировать, что побочный эффект применяется только один раз)

#define quad(x) (x*x)
int i = 1;
int a = quad(i++);

будет расширяться до:

int a = i++ * i++;

Ответ 5

Так как 100 - это единственный токен, я сомневаюсь, что вы найдете угловой случай, где имеют значение круглые скобки (для одного токена!)

Это по-прежнему хорошая привычка ИМО, поскольку они могут иметь значение, когда задействованы несколько токенов.

Ответ 6

Нет. Нет случая, когда #define WIDTH 100 может дать однозначное или "неожиданное" расширение. Это потому, что это может привести только к замене одного токена на один токен.

Как вы знаете, путаница макросов возникает, когда один токен (например, WIDTH) приводит к нескольким токенам (например, 80 + 20). Насколько я могу судить, единственная причина использования круглых скобок в подстановках и, как описано в моем первом абзаце, здесь не применяется.

Однако этот технический факт в стороне, это может быть хорошей практикой. Это способствует привычке, и это также служит напоминанием, если этот макрос когда-либо изменен на нечто более сложное.

Ответ 7

Когда код определяет только число, @Alexander Gessler отвечает на вопрос.

Однако многие кодеры не замечают унарных операторов в следующем:

#define TEMPERATURE1M (-1)
#define TEMPERATURE1P (+1)

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

#define TEMPERATURE_WITH  (-1)
#define TEMPERATURE_WITHOUT -1

// Consider how these will compile
int w  = 10-TEMPERATURE_WITH;
int wo = 10-TEMPERATURE_WITHOUT;  // May not compile

Последняя строка кода может скомпилировать заданные семантические изменения C99 @Olaf

Ответ 8

Есть веская причина, иногда.

Для одного номера нет веской причины.

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

Некоторые люди предпочитают быть более осторожными и всегда использовать круглые скобки (@aix рекомендует его. Я не знаю, но нет жесткого ответа).

Ответ 9

Конечно, это не повредит, и это хорошая привычка. Но для численных расчетов нет разницы между (100) и 100.