Может ли определение макроса C ссылаться на другие макросы?

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

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

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

MEH

с

(15 / 23)

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

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

Ответ 1

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

Ответ 2

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

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

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

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

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

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

Ответ 3

Да, он будет работать.


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

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

  • Полезное ключевое слово для предварительного процессора: #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))

Ответ 4

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

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

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

#define FOO 1
#define FSMACRO(x) FOO + x

Ответ 5

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

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

#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

Ответ 6

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

#define STR "string"
void main() { printf("value=%s\n", VALUE); }

В командной строке вы можете сказать, что макрос "VALUE" принимает значение из другого макроса "STR":

$ gcc -o test_macro -DVALUE=STR main.c
$ ./test_macro

Выход:

value=string

Этот подход работает также и для компилятора MSC в Windows. Я нахожу это очень гибким.