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

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

#error BOOST_VERSION

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

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

Ответ 1

Если вы используете Visual С++, вы можете использовать #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)

Ответ 2

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

Ответ 3

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

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

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

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

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

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

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

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

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

Ответ 4

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

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

Ответ 5

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

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

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

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

[email protected]:~/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 ()
{

}

Ответ 6

#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 & lt; :: '*/' # & gt;

Ответ 7

В 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

Ответ 8

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

Ответ 9

Вы ищете

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

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

Ответ 10

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

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

Ответ 11

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

Ответ 12

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

Ответ 13

Взгляните также на документацию 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) является основным версия.