web-dev-qa-db-fra.com

Comment puis-je afficher la valeur d'un #define au moment de la compilation?

J'essaie de déterminer quelle version de Boost mon code pense utiliser. Je veux faire quelque chose comme ça:

#error BOOST_VERSION

mais le préprocesseur ne développe pas BOOST_VERSION.

Je sais que je pourrais l’imprimer au moment de l’exécution à partir du programme, et je pourrais aussi regarder la sortie du pré-processeur pour trouver la réponse. Je pense qu’il serait utile d’avoir un moyen de faire cela pendant la compilation.

108
Jim Hunziker

Si vous utilisez Visual C++, vous pouvez utiliser #pragma message:

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

Edit: Merci à LB pour le lien

Apparemment, l'équivalent GCC est (non testé):

#pragma message "BOOST_VERSION=" BOOST_PP_STRINGIZE(BOOST_VERSION)
57
Bojan Resnik

BOOST_PP_STRINGIZE semble une excellente solution pour le C++, mais pas pour le C. ordinaire.

Voici ma solution pour 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))

Les définitions ci-dessus donnent:

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"

Pour les variables "défini en tant qu'interger", "défini en tant que chaîne", et "défini mais sans valeur", elles fonctionnent parfaitement. Seulement pour la variable "non définie", ils affichent exactement le même nom que le nom de la variable d'origine. Vous devez être habitué - ou peut-être que quelqu'un peut fournir une meilleure solution.

111
Jackie Yeh

Je sais que cela fait longtemps après la requête initiale, mais cela peut encore être utile.

Cela peut être fait dans GCC en utilisant l'opérateur stringify "#", mais cela nécessite deux étapes.

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

La valeur d'une macro peut ensuite être affichée avec:

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

Voir: 3.4 Stringification dans la documentation en ligne de gcc.

Comment ça marche:

Le préprocesseur comprend les chaînes entre guillemets et les traite différemment du texte normal. La concaténation de chaînes est un exemple de ce traitement spécial. Le pragma du message nécessite un argument qui est une chaîne entre guillemets. Lorsqu'il y a plus d'un composant dans l'argument, ils doivent tous être des chaînes pour que la concaténation de chaînes puisse être appliquée. Le préprocesseur ne peut jamais supposer qu'une chaîne non citée doit être traitée comme si elle était entre guillemets. Si c'était le cas alors:

#define ABC 123
int n = ABC;

ne pas compiler.

Considérons maintenant:

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

ce qui équivaut à

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

Cela provoque un avertissement de préprocesseur car abc (non entre guillemets) ne peut pas être concaténé avec la chaîne précédente.

Maintenant, considérons la chaîne stringing du préprocesseur (ce qui était autrefois appelé stringification, les liens dans la documentation ont été modifiés pour refléter la terminologie révisée. (Les deux termes, incidemment, sont également détestables. Le terme correct est, bien sûr, stringifaction. vos liens.)) opérateur. Cela n'agit que sur les arguments d'une macro et remplace l'argument non développé par l'argument placé entre guillemets. Ainsi:

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

attribuera des valeurs identiques à s1 et s2. Si vous exécutez gcc -E, vous pouvez le voir dans la sortie. Peut-être que STR serait mieux nommé quelque chose comme ENQUOTE.

Cela résout le problème de placer des guillemets autour d'un élément non cité, le problème est maintenant que, si l'argument est une macro, la macro ne sera pas développée. C'est pourquoi la deuxième macro est nécessaire. XSTR développe son argument, puis appelle STR pour mettre la valeur développée entre guillemets.

91
Chris Barry

Pour autant que je sache, '#error' n'imprimera que des chaînes, en fait vous n'avez même pas besoin d'utiliser des guillemets .

Avez-vous essayé d'écrire divers codes intentionnellement incorrects en utilisant "BOOST_VERSION"? Peut-être quelque chose comme "bla [BOOST_VERSION] = foo;" vous dira quelque chose comme "le littéral de chaîne 1.2.1 ne peut pas être utilisé comme adresse de tableau". Ce ne sera pas un joli message d'erreur, mais au moins, il vous montrera la valeur pertinente. Vous pouvez jouer jusqu'à ce que vous trouviez une erreur de compilation qui vous indique la valeur.

13
KeyserSoze

Sans boost:

  1. définissez à nouveau la même macro et le compilateur HIMSELF vous avertira.

  2. De l'avertissement, vous pouvez voir l'emplacement de la définition précédente.

  3. fichier vi de la définition précédente.

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

}
11
#define a <::BOOST_VERSION>
#include a
MSVC2015: erreur fatale C1083: impossible d'ouvrir le fichier d'inclusion: ':: 106200': aucun fichier ou répertoire de ce type

Fonctionne même si preprocess to file est activé, même si des jetons non valides sont présents:

#define a <::'*/`#>
#include a
MSVC2015: erreur fatale C1083: impossible d'ouvrir le fichier d'inclusion: '::' */`# ': aucun fichier ou répertoire de ce type
GCC4.x: avertissement: caractère de fin manquant [-Winvalid-pp-token]
# définir un <:: '*/`#>
5
Andry

Dans Microsoft C/C++, vous pouvez utiliser la fonction intégrée _CRT_STRINGIZE() pour imprimer des constantes. Beaucoup de mes stdafx.h Les fichiers contiennent une combinaison de ceux-ci:

#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)) 

et sort quelque chose comme ceci:

_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
4
UweBaemayr

Vous pouvez également prétraiter le fichier source et voir à quoi correspond la valeur du préprocesseur.

3
fbrereto

Cherchez-vous

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

Pas génial si BOOST_VERSION est une chaîne, comme je l'ai supposé, mais il peut également y avoir des entiers individuels définis pour les numéros majeur, mineur et de révision.

2
user47559

En regardant la sortie du préprocesseur est la chose la plus proche de la réponse que vous demandez.

Je sais que vous avez exclu cela (et d'autres manières), mais je ne sais pas pourquoi. Vous avez un problème assez spécifique à résoudre, mais vous n'avez pas expliqué pourquoi l'une des méthodes "normales" ne fonctionne pas bien pour vous.

2
dwc

Consultez également la documentation Boost concernant votre utilisation de la macro:

En référence à BOOST_VERSION, de 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 =:

Décrit le numéro de version de boost au format XXYYZZ tel que: (BOOST_VERSION % 100) est la version secondaire, ((BOOST_VERSION / 100) %1000) est la version mineure et (BOOST_VERSION / 100000) est la version majeure.

1
bn.

BOOST_VERSION est défini dans le fichier d’en-tête de démarrage version.hpp.

1
David Harris

Vous pourriez écrire un programme qui imprime BOOST_VERSION et compilez-le et exécutez-le dans le cadre de votre système de construction. Sinon, je pense que vous n'avez pas de chance.

1
Chris Lutz