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

Препроцессор C: расширение макроса в #warning

Я хотел бы напечатать макрокоманду (развернуть макрос) в директиве #warning.

Например, для кода:

#define AAA 17
#warning AAA = ???

Желаемый результат компиляции -

warning: AAA = 17

Что я использую для?, или, как мне увеличить код?

4b9b3361

Ответ 1

Вы можете использовать директиву препроцессора #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))
         ^

Для справки:

Ответ 2

Я бы не рекомендовал использовать #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, чтобы включить его.

Ответ 3

Если вы действительно хотите выпустить предупреждение, будет работать и следующее. Тем не менее, это зависит от включенности 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

Ответ 4

Много раз у меня есть файл Makefile, создающий локальный файл сгенерированный .h, который содержит нужные определения.

generated.h:  Makefile
        echo >generated.h "// WARNING: generated file. Change Makefile instead"
        date >>generated.h '+//   generated on %Y-%m-%d %H:%M:%S'
        echo >>generated.h "#if AAA == AAA_bad"
        echo >>generated.h "#warning \"AAA = $(AAA_bad)\""
        echo >>generated.h "#endif"

Необходимость #include "сгенерирована .h" очевидна.

Естественно, вы можете наворотить любую сложность здесь, но если он получит больше, чем несколько строк, вы можете хотите поместить сложность в отдельный script, поскольку загроможденные Make файлы могут быть ужасными обслуживание проблема. С небольшим воображением вы можете иметь петли, генерирующие большое количество тестов с небольшого ввода.

Наличие цели сгенерированного .h зависит от Makefile имеет решающее значение для обеспечения сгенерированного .h переделано, если команды в целевом изменении. Если у вас есть отдельный сгенерированный .sh script, который тоже будет в списке зависимостей.

Отказ от ответственности: не проверены на реальность.