Как мне показать значение #define во время компиляции?

StackOverflow https://stackoverflow.com/questions/1562074

Вопрос

Я пытаюсь выяснить, какую версию Boost, по мнению моего кода, он использует.Я хочу сделать что-то вроде этого:

#error BOOST_VERSION

но препроцессор не расширяет BOOST_VERSION.

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

Это было полезно?

Решение

Если вы используете Visual C ++, вы можете использовать #pragma message:

#include <boost/preprocessor/stringize.hpp>
#pragma message("BOOST_VERSION=" BOOST_PP_STRINGIZE(BOOST_VERSION))

Редактировать: Спасибо LB за ссылку

По-видимому, эквивалент GCC (не тестировался):

#pragma message "BOOST_VERSION=" BOOST_PP_STRINGIZE(BOOST_VERSION)

Другие советы

BOOST_PP_STRINGIZE кажется отличным решением для C ++, но не для обычного C.

Вот мое решение для GNU CPP:

/* Some test definition here */
#define DEFINED_BUT_NO_VALUE
#define DEFINED_INT 3
#define DEFINED_STR "ABC"

/* definition to expand macro then apply to pragma message */
#define VALUE_TO_STRING(x) #x
#define VALUE(x) VALUE_TO_STRING(x)
#define VAR_NAME_VALUE(var) #var "="  VALUE(var)

/* Some example here */
#pragma message(VAR_NAME_VALUE(NOT_DEFINED))
#pragma message(VAR_NAME_VALUE(DEFINED_BUT_NO_VALUE))
#pragma message(VAR_NAME_VALUE(DEFINED_INT))
#pragma message(VAR_NAME_VALUE(DEFINED_STR))

Приведенные выше определения приводят к:

test.c:10:9: note: #pragma message: NOT_DEFINED=NOT_DEFINED
test.c:11:9: note: #pragma message: DEFINED_BUT_NO_VALUE=
test.c:12:9: note: #pragma message: DEFINED_INT=3
test.c:13:9: note: #pragma message: DEFINED_STR="ABC"

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

Я знаю, что прошло много времени после первоначального запроса, но это все еще может быть полезно.

Это можно сделать в GCC с помощью оператора stringify "#", но для этого требуется два этапа.

#define XSTR(x) STR(x)
#define STR(x) #x

Затем значение макроса может быть отображено с помощью:

#pragma message "The value of ABC: " XSTR(ABC)

Видишь:3.4 Строкообразование в онлайн-документации gcc.

Как это работает:

Препроцессор понимает строки, заключенные в кавычки, и обрабатывает их иначе, чем обычный текст.Конкатенация строк является примером такой специальной обработки.Для прагмы message требуется аргумент, представляющий собой строку, заключенную в кавычки.Если в аргументе имеется более одного компонента, то все они должны быть строками, чтобы можно было применить конкатенацию строк.Препроцессор никогда не может предположить, что строка без кавычек должна обрабатываться так, как если бы она была заключена в кавычки.Если бы это произошло , то:

#define ABC 123
int n = ABC;

не будет компилироваться.

Теперь рассмотрим:

#define ABC abc
#pragma message "The value of ABC is: " ABC

что эквивалентно

#pragma message "The value of ABC is: " abc

Это вызывает предупреждение препроцессора, поскольку abc (без кавычек) не может быть объединен с предыдущей строкой.

Теперь рассмотрим stringize препроцессора (который когда-то назывался stringification, ссылки в документации были изменены, чтобы отразить пересмотренную терминологию.(Кстати, оба термина одинаково отвратительны.Правильный термин - это, конечно, stringifaction .Будьте готовы обновлять свои ссылки.)) оператор.Это действует только на аргументы макроса и заменяет нерасширенный аргумент аргументом, заключенным в двойные кавычки.Таким образом:

#define STR(x) #x
char *s1 = "abc";
char *s2 = STR(abc);

присвоит идентичные значения s1 и s2.Если вы запустите gcc -E, вы можете увидеть это в выходных данных.Возможно, STR было бы лучше назвать как-то вроде ENQUOTE.

Это решает проблему размещения кавычек вокруг элемента без кавычек, проблема теперь в том, что, если аргументом является макрос, макрос не будет расширен.Вот почему необходим второй макрос.XSTR расширяет свой аргумент, затем вызывает STR, чтобы заключить расширенное значение в кавычки.

Насколько я знаю, '#error' на самом деле выводит только строки вам даже не нужно использовать кавычки.

Вы пробовали писать различный намеренно неправильный код, используя "BOOST_VERSION"?Возможно, что-то вроде "blah[BOOST_VERSION] = foo;" скажет вам что-то вроде "строковый литерал 1.2.1 не может использоваться в качестве адреса массива".Это не будет красивым сообщением об ошибке, но, по крайней мере, оно покажет вам соответствующее значение.Вы можете поиграть до тех пор, пока не обнаружите ошибку компиляции, которая действительно сообщает вам значение.

Без наддува :

  1. определите тот же макрос еще раз, и компилятор САМ выдаст предупреждение.

  2. Из предупреждения вы можете увидеть местоположение предыдущего определения.

  3. vi файл предыдущего определения .

ambarish@axiom:~/cpp$ g++ shiftOper.cpp
shiftOper.cpp:7:1: warning: "LINUX_VERSION_CODE" redefined
shiftOper.cpp:6:1: warning: this is the location of the previous definition

#define LINUX_VERSION_CODE 265216
#define LINUX_VERSION_CODE 666

int main ()
{

}
#define a <::BOOST_VERSION>
#include a
MSVC2015:неустранимая ошибка C1083:Не удается открыть включаемый файл:'::106200':Такого файла или каталога нет

Работает, даже если preprocess to file включен, даже если присутствуют недопустимые токены:

#define a <::'*/`#>
#include a
MSVC2015:неустранимая ошибка C1083:Не удается открыть включаемый файл:'::'*/`#':Такого файла или каталога нет
GCC4.x:предупреждение:отсутствующий завершающий символ [-Winvalid-pp-token]
#определить <::'*/`#>

В Microsoft C/C ++ вы можете использовать встроенный _CRT_STRINGIZE() для печати констант.Многие из моих stdafx.h файлы содержат некоторую комбинацию этих:

#pragma message("_MSC_VER      is " _CRT_STRINGIZE(_MSC_VER))
#pragma message("_MFC_VER      is " _CRT_STRINGIZE(_MFC_VER))
#pragma message("_ATL_VER      is " _CRT_STRINGIZE(_ATL_VER))
#pragma message("WINVER        is " _CRT_STRINGIZE(WINVER))
#pragma message("_WIN32_WINNT  is " _CRT_STRINGIZE(_WIN32_WINNT))
#pragma message("_WIN32_IE     is " _CRT_STRINGIZE(_WIN32_IE))
#pragma message("NTDDI_VERSION is " _CRT_STRINGIZE(NTDDI_VERSION)) 

и выводит что-то вроде этого:

_MSC_VER      is 1915
_MFC_VER      is 0x0E00
_ATL_VER      is 0x0E00
WINVER        is 0x0600
_WIN32_WINNT  is 0x0600
_WIN32_IE     is 0x0700
NTDDI_VERSION is 0x06000000

Вы также можете предварительно обработать исходный файл и посмотреть, каково значение препроцессора.

Вы ищете

#if BOOST_VERSION != "1.2"
#error "Bad version"
#endif

Не очень хорошо, если BOOST_VERSION является строкой, как я предполагал, но также могут быть отдельные целые числа, определенные для основного, второстепенного номеров и номеров версий.

Просмотр выходных данных препроцессора - это самое близкое к ответу, который вы запрашиваете.

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

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

BOOST_VERSION определен в заголовочном файле boost version.hpp.

Взгляните также на документацию Boost о том, как вы используете макрос:

В отношении BOOST_VERSION, из http://www.boost.org/doc/libs/1_37_0/libs/config/doc/html/boost_config/boost_macro_reference.html#boost_config.boost_macro_reference.boost_helper_macros:

Описывает номер версии boost в формате XXYYZZ таким образом, что: (BOOST_VERSION % 100) является второстепенным версия, ((BOOST_VERSION / 100) % 1000) является второстепенной версией, и (BOOST_VERSION / 100000) является основной версия.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top