Je souhaite créer une macro C qui crée une fonction avec un nom basé sur le numéro de ligne. Je pensais que je pourrais faire quelque chose comme (la fonction réelle aurait des déclarations entre accolades):
#define UNIQUE static void Unique_##__LINE__(void) {}
Ce que j'espérais étendre à quelque chose comme:
static void Unique_23(void) {}
Cela ne marche pas. Avec la concaténation de jetons, les macros de positionnement sont traitées littéralement, finissant par s'étendre en:
static void Unique___LINE__(void) {}
Est-ce possible?
(Oui, il y a une vraie raison pour laquelle je veux faire cela, même si cela semble inutile).
__LINE__
(bien que ce soit un cas d'utilisation courant.Réponses:
Le problème est que lorsque vous avez un remplacement de macro, le préprocesseur ne développera les macros de manière récursive que si ni l'opérateur de stringizing
#
ni l'opérateur de collage de jetons ne lui##
sont appliqués. Donc, vous devez utiliser des couches supplémentaires d'indirection, vous pouvez utiliser l'opérateur de collage de jetons avec un argument étendu de manière récursive:Ensuite,
__LINE__
obtient étendu au numéro de ligne lors de l'expansion deUNIQUE
(puisqu'il n'est pas impliqué soit#
ou##
), puis le coller jeton se produit lors de l'expansion deTOKENPASTE
.Il convient également de noter qu'il existe également la
__COUNTER__
macro, qui se développe en un nouvel entier à chaque fois qu'elle est évaluée, au cas où vous auriez besoin de plusieurs instanciations de laUNIQUE
macro sur la même ligne. Remarque:__COUNTER__
est pris en charge par MS Visual Studio, GCC (depuis V4.3) et Clang, mais n'est pas standard C.la source
__COUNTER__
macro ne fonctionnait pas pour moi dans gcc; bien que celui-__LINE__
ci ait fonctionné comme annoncé.GCC ne nécessite pas de "wrapping" (ou de réalisation) sauf si le résultat doit être "stringifié". Gcc a des fonctionnalités mais TOUT peut être fait avec la version 1 en C (et certains affirment que Berkeley 4.3 C est tellement plus rapide qu'il vaut la peine d'apprendre à l'utiliser).
** Clang (llvm) NE FAIT PAS CORRECTEMENT L'ESPACE BLANC pour l'expansion des macros - il ajoute des espaces (ce qui détruit certainement le résultat comme étant un identificateur C pour un prétraitement ultérieur) **, clang ne fait tout simplement pas # ou * l'expansion des macros comme un préprocesseur C devrait le faire pendant des décennies. Le premier exemple est la compilation de X11, la macro "Concat3" est cassée, son résultat est maintenant MISNAMED C Identifier, qui échoue bien sûr à construire. et je commence à faire des échecs de construction.
Je pense que la réponse ici est "le nouveau C qui enfreint les normes est mauvais C", ces hacks choisissent toujours de (écraser les espaces de noms), ils changent les valeurs par défaut sans raison mais ne "améliorent pas vraiment C" (sauf à leur propre avis: ce que je disons qu'un engin est fait pour expliquer pourquoi ils s'en sortent avec tous les bris dont personne ne les a encore rendus responsables).
Ce n'est pas un problème que les préprocesseurs C précédents ne supportaient pas UNIq_ () __ car ils supportaient #pragma qui permet au "piratage de la marque du compilateur dans le code d'être signalé comme du piratage" et de fonctionner aussi bien SANS affecter les normes: tout comme changer les valeurs par défaut sont inutiles, et tout comme changer ce qu'une fonction fait tout en utilisant le même nom (coupure d'espace de noms) est ... un malware à mon avis
la source