web-dev-qa-db-fra.com

Préprocesseur C: développez la macro dans un #warning

Je voudrais imprimer une valeur de macro (développer la macro) dans la directive #warning.

Par exemple, pour le code:

#define AAA 17
#warning AAA = ???

La sortie de compilation souhaitée serait

warning: AAA = 17

Qu'est-ce que j'utilise pour ???, ou comment puis-je augmenter le code?

38
elomage

Vous pouvez utiliser la directive de préprocesseur #pragma message.

Exemple:

#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; }

La sortie peut ressembler à ceci:

$ gcc test.c
test.c:5:9: note: #pragma message: content of AAA: 123
 #pragma message("content of AAA: " STR(AAA))
         ^

Pour référence:

46
moooeeeep

Si vous voulez vraiment émettre un avertissement, ce qui suit fonctionnera également. Cependant, cela dépend de l'activation de C99 (fonctionne avec gcc 4.8.2 ou version ultérieure, non testé sur les versions antérieures):

#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
8
Aconcagua

Je ne recommanderais pas d'utiliser #warning, car ce n'est pas le standard C. De plus, contre quoi voulez-vous mettre en garde sans lancer d'erreur? Les avertissements sont généralement quelque chose que le compilateur utilise lorsque vous faites quelque chose qui est suspect ou carrément dangereux, mais autorisé par la norme C. Vous n'avez pas un tel cas dans une application normale, vous voudrez qu'il soit compilé parfaitement ou pas du tout. Par conséquent, j'utiliserais #error standard et non #warning non standard.

Vous ne pouvez pas saisir le contenu réel de la définition du pré-processeur. Quelque chose comme ça pourrait suffire:

#if (AAA < SOMETHING) && (AAA > SOMETHING_ELSE)
  #error AAA is bad.
#endif

Je pense que c'est assez détaillé pour le programmeur. Cependant, si vous vraiment voulez plus de détails et que vous avez un compilateur C moderne, vous pouvez utiliser static_assert . Ensuite, vous pouvez réaliser quelque chose de proche de ce que vous voulez:

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

ce désordre de macro devrait imprimer AAA est 17. Une explication sur la façon dont ces macros fonctionnent peut être trouvée ici .

Je ne sais pas si static_assert était inclus dans C99 ou C11, c'est certainement dans C11. Vous devrez peut-être utiliser une extension GCC pour l'activer.

7
Lundin

Plusieurs fois, mon Makefile génère un fichier local generated.h qui contient les définitions souhaitées.

 généré.h: Makefile 
 echo> généré.h "// AVERTISSEMENT: fichier généré. Modifiez le Makefile à la place" 
 date >> généré.h '+ // généré sur% Y-% m-% d% H:% M:% S '
 Écho >> généré.h "#if AAA == AAA_bad" 
 Écho >> généré.h "#warning\"AAA = $ (AAA_bad) \" "
 Echo >> généré.h" #endif "

Le besoin de #include "generated.h" est évident.

Naturellement, vous pouvez faire tourner n'importe quelle complexité ici, mais si cela devient plus que quelques lignes, vous voudrez peut-être mettre la complexité dans un script séparé car les Makefiles encombrés peuvent être un horrible problème de maintenance. Avec un peu d'imagination, vous pouvez avoir des boucles générant un grand nombre de tests à partir d'une petite entrée.

Faire en sorte que la cible générée.h dépende de Makefile est essentiel pour garantir que la génération.h est refaite si les instructions de la cible changent. Si vous avez un script generate.sh distinct qui serait également sur la liste des dépendances.

Avertissement: n'ont pas testé pour de vrai.

2
Gilbert