Может ли определение макроса C ссылаться на другие макросы? - PullRequest
36 голосов
/ 02 ноября 2011

Я пытаюсь выяснить, если что-то вроде этого (написано в C ):

#define FOO 15
#define BAR 23
#define MEH (FOO / BAR)

разрешено? Я хотел бы, чтобы препроцессор заменял каждый экземпляр

MEH

с

(15 / 23)

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

Я нашел несколько похожих примеров, но все они были действительно слишком сложны для меня, чтобы понять. Если бы кто-то мог помочь мне с этим простым, я был бы вечно благодарен!

Ответы [ 5 ]

31 голосов
/ 02 ноября 2011

Краткий ответ да. Вы можете вкладывать определения и подобные макросы - столько уровней, сколько вы хотите, если это не является рекурсивным.

26 голосов
/ 02 ноября 2011

Ответ «да», и два других человека правильно сказали так.

Что касается почему ответ - да, кровавые подробности в стандарте C, раздел 6.10.3.4, «Повторное сканирование и дальнейшая замена».OP может не получить выгоды от этого, но другие могут быть заинтересованы.

6.10.3.4 Повторное сканирование и дальнейшая замена

После того, как все параметры в списке замены имеютбыла заменена, и # и ## обработка была выполнена, все маркеры предварительной обработки меток были удалены.Затем результирующая последовательность токенов предварительной обработки пересканируется вместе со всеми последующими токенами предварительной обработки исходного файла для замены других имен макросов.

Если имя заменяемого макроса найдено во время этого сканирования заменысписок (не включая остальные токены предварительной обработки исходного файла), он не заменяется.Кроме того, если во вложенных заменах встречается имя заменяемого макроса, он не заменяется.Эти невзаимозаменяемые токены предварительной обработки имен макросов больше не доступны для дальнейшей замены, даже если они позднее (повторно) проверяются в тех контекстах, в которых в противном случае этот токен предварительной обработки имен макросов был бы заменен.последовательность токенов не обрабатывается как директива предварительной обработки, даже если она похожа на единицу, но все прагматические выражения унарного оператора внутри нее затем обрабатываются, как указано в 6.10.9 ниже.

14 голосов
/ 02 ноября 2011

Да, это сработает.


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

  • Определения «определены» в порядке их включения / чтения. Это означает, что вы не можете использовать определение, которое не было определено ранее.

  • Полезное ключевое слово препроцессора: #define, #undef, #else, #elif, #ifdef, #ifndef, # if

  • Вы можете использовать любой другой ранее #define в вашем макросе. Они будут расширены. (как в вашем вопросе)

  • Определения макроса функций принимают два специальных оператора (# и ##)

operator # stringize аргумент:

#define str(x) #x
str(test); // would translate to "test"

оператор ## объединяет два аргумента

#define concat(a,b) a ## b
concat(hello, world); // would translate to "helloworld"

Также есть несколько предопределенных макросов (из языка), которые вы можете использовать:

__LINE__, __FILE__, __cplusplus, etc

Смотрите в разделе вашего компилятора обширный список, поскольку он не "кроссплатформенный"

  • Обратите внимание на расширение макроса

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

#define mult(a, b) a * b
mult(1+2, 3+4); // will be expanded like: 1 + 2 * 3 + 4 = 11 instead of 21.
mult_fix(a, b) ((a) * (b))
2 голосов
/ 14 февраля 2018

Я хотел бы добавить ошибку, которая споткнула меня.

Макросы в стиле функции не могут сделать это.

Пример, который не компилируется при использовании:

#define FOO 1
#define FSMACRO(x) FOO + x
0 голосов
/ 02 ноября 2011

Да, это поддерживается. И использовал довольно много!

Одна важная вещь, которую стоит отметить, - это убедиться, что вы выражаете выражение, иначе вы можете столкнуться с неприятными проблемами!

#define MEH FOO/BAR

// vs

#define MEH (FOO / BAR)

// the first could be expanded in an expression like 5 * MEH to mean something 
//   completely different than the second
...