Препроцессор C: разверните макрос в предупреждении
Я хотел бы напечатать значение макроса (разверните макрос) в директиве #warning.
Например, для кода:
#define AAA 17
#warning AAA = ???
Желаемый вывод времени компиляции будет
warning: AAA = 17
Что я использую для??? или как дополнить код?
5 ответов
Вы можете использовать директиву препроцессора #pragma message
,
Пример:
#define STR_HELPER(x) #x
#define STR(x) STR_HELPER(x)
#define AAA 123
#pragma message "content of AAA: " STR(AAA)
int main() { return 0; }
Вывод может выглядеть так:
$ gcc test.c
test.c:5:9: note: #pragma message: content of AAA: 123
#pragma message("content of AAA: " STR(AAA))
^
Для справки:
Если вы действительно хотите выдать предупреждение, сработает также следующее. Однако это зависит от того, включен ли C99 (работает с gcc 4.8.2 или новее, не тестировался в более ранних версиях):
#define N 77
#define __STRINGIFY(TEXT) #TEXT
#define __WARNING(TEXT) __STRINGIFY(GCC warning TEXT)
#define WARNING(VALUE) __WARNING(__STRINGIFY(N = VALUE))
#if N == 77
_Pragma (WARNING(N))
#endif
Я бы не рекомендовал использовать #warning, так как это не стандартная версия C. Кроме того, что вы хотите предупредить, но не выдать ошибку? Предупреждения - это, как правило, то, что компилятор использует, когда вы делаете что-то подозрительное, что мы опасно, но допускается стандартом C. У вас нет такого случая в обычном приложении, вы захотите, чтобы оно компилировалось без ошибок или вообще не компилировалось. Поэтому я бы использовал стандартный #error, а не нестандартный #warning.
Вы не можете ввести фактическое содержание определения препроцессора. Что-то вроде этого может быть достаточно:
#if (AAA < SOMETHING) && (AAA > SOMETHING_ELSE)
#error AAA is bad.
#endif
Я думаю, что это достаточно подробно для программиста. Однако, если вы действительно хотите больше подробностей и у вас есть современный компилятор C, вы можете использовать static_assert. Тогда вы можете достичь чего-то близкого к тому, что вы хотите:
#include <assert.h>
#define xstr(s) str(s)
#define str(s) #s
#define err_msg(x) #x " is " xstr(x)
#define AAA 17
static_assert(AAA != 17, err_msg(AAA));
этот макрос беспорядок должен печатать AAA 17. Объяснение того, как работают эти макросы, можно найти здесь.
Я не уверен, был ли static_assert включен в C99 или C11, это, безусловно, в C11. Возможно, вам придется использовать какое-то расширение GCC, чтобы включить его.
Много раз у меня Makefile генерировал локальный сгенерированный файл.h, который содержит нужные определения.
Генерируемый.h: Makefile echo >generate.h "// ПРЕДУПРЕЖДЕНИЕ: сгенерированный файл. Вместо этого измените Makefile" дата >> сгенерировано.h '+// сгенерировано на%Y-%m-%d %H:%M:%S' echo >>generate.h "#if AAA == AAA_bad" echo >>generate.h "#warning \"AAA = $(AAA_bad)\"" echo >>generate.h "#endif"
Необходимость в #include "generate.h" очевидна.
Естественно, вы можете вращать здесь любую сложность, но если она получает больше, чем несколько строк, вы можете поместить сложность в отдельный скрипт, так как загроможденные Make-файлы могут быть проблемой обслуживания. С небольшим воображением у вас могут быть циклы, генерирующие большое количество тестов из небольшого ввода.
Наличие цели target.h, зависящей от Makefile, имеет решающее значение для гарантии того, что генерируемый файл переделывается, если инструкции в цели меняются. Если у вас есть отдельный сгенерированный скрипт.sh, он тоже будет в списке зависимостей.
Отказ от ответственности: не проверено на реальные.
Еще один простой метод, особенно когда вы имеете дело с проектом Makefile (например, linux, u-boot, qemu, ..), вы можете увидеть предварительно обработанный результат файла.
Например,
чтобы увидеть предварительно обработанный файл
arch/arm64/kernel/head.S
,
вы можете сделать
arch/arm64/kernel/head.s
. (маленькая с).
чтобы увидеть предварительно обработанный файл
foo/bar/baz.c
,
вы можете сделать
foo/bar/baz.i
Все макросы расширены до конечного значения.