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

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

#error BOOST_VERSION

но препроцессор не раскрывает BOOST_VERSION.

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

13 ответов

Решение

Если вы используете 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)

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

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

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

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

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

См.: 3.4 Стрификация в онлайн-документации gcc.

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"

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

Без повышения:

  1. снова определите тот же макрос, и компилятор HIMSELF выдаст предупреждение.

  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 ()
{

}

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

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

В 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
#define a <::BOOST_VERSION>
#include a
MSVC2015: неустранимая ошибка C1083: невозможно открыть включаемый файл: '::106200': такого файла или каталога нет

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

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

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

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

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

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

Вы ищете

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

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

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

Что касается BOOST_VERSION из http://www.boost.org/doc/libs/1_37_0/libs/config/doc/html/boost_config/boost_macro_reference.html:

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

BOOST_VERSION определяется в файле заголовка надстройки version.hpp.

Вместо #error попробуйте переопределить макрос непосредственно перед его использованием. Компиляция завершится ошибкой, и компилятор предоставит текущее значение, которое, по его мнению, применимо к макросу.

#define BOOST_VERSION blah

Другие вопросы по тегам