web-dev-qa-db-fra.com

Création d'une macro C avec ## et __LINE__ (concaténation de jetons avec macro de positionnement)

Je veux créer une macro C qui crée une fonction avec un nom basé sur le numéro de ligne. J'ai pensé que je pouvais faire quelque chose comme (la vraie fonction aurait des instructions entre accolades):

#define UNIQUE static void Unique_##__LINE__(void) {}

Ce que j'espérais étendre à quelque chose comme:

static void Unique_23(void) {}

Ça ne marche pas. Avec la concaténation de jetons, les macros de positionnement sont traitées littéralement, finissant par s'étendre à:

static void Unique___LINE__(void) {}

Est-ce possible?

(Oui, il y a une vraie raison pour laquelle je veux le faire, même si cela semble inutile).

100
DD.

Le problème est que lorsque vous avez un remplacement de macro, le préprocesseur ne développera les macros que de manière récursive si ni l'opérateur de mise en chaîne # ni l'opérateur de collage de jetons ## 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 développé récursivement:

#define TOKENPASTE(x, y) x ## y
#define TOKENPASTE2(x, y) TOKENPASTE(x, y)
#define UNIQUE static void TOKENPASTE2(Unique_, __LINE__)(void) {}

Ensuite, __LINE__ est étendu au numéro de ligne lors de l'expansion de UNIQUE (puisqu'il n'est impliqué ni avec # ou ##), puis le collage de jetons se produit lors de l'expansion de TOKENPASTE.

Il convient également de noter qu'il existe également le __COUNTER__ macro, qui se développe en un nouvel entier chaque fois qu'il est évalué, au cas où vous auriez besoin d'avoir plusieurs instanciations de la macro UNIQUE sur la même ligne. Remarque: __COUNTER__ est pris en charge par MS Visual Studio, GCC (depuis la version 4.3) et Clang, mais n'est pas le standard C.

165
Adam Rosenfield