2017-02-19 2 views
2

J'écris des bibliothèques pour un microcontrôleur, et à cette fin, j'utilise des fonctions de type macro. Par exemple, une fonction de macro-like pour permettre à un module de I2C est défini comme:Concaténation des constantes macro en utilisant ##

#define I2C_MODULE_ENABLE(_x) \ 
    I2C##_x##CONLbits.I2CEN = 1 

_x est le nombre de modules (par exemple, 1 ou 2 dans mon cas).

Si un utilisateur appelle cette fonction de type macro comme I2C_MODULE_ENABLE(1), il sera développé par un préprocesseur sous la forme I2C1CONLbits. I2CEN = 1.

Cependant, si un utilisateur appelle cette fonction macro semblable comme I2C_MODULE_ENABLE(MY_I2C), où MY_I2C est une constante macro définie dans un fichier config.h défini par l'utilisateur qui est inclus par ma bibliothèque i2c.h (par exemple, la constante macro est définie comme #define MY_I2C 1) , la fonction de type macro serait étendue en tant que I2CMY_I2CCONLbits. I2CEN = 1.

Je sais que je dois évaluer en quelque sorte la MY_I2C constante macro avant concaténation, et je peux le faire en ajoutant un autre niveau macro:

#define __I2CxCONLbits(_x) I2C##_x##CONLbits 
#define I2C_MODULE_ENABLE(_x) \ 
    __I2CxCONLbits.I2CEN = 1 

Ma question est: est-il une solution plus élégante à ce problème puisque j'ai plusieurs registres comme le registre CONLbits. En utilisant cette approche, je devrais définir une macro spéciale __I2CxREGISTER(_x) pour chaque registre.

J'ai essayé de faire quelque chose comme ceci:

#define __I2Cx(_x) I2C##_x 
#define I2C_MODULE_ENABLE(_x) \ 
    __I2Cx(_x)##CONLbits.I2CEN = 1 

mais qui produit une sortie comme ceci: I2C1 CONLbits .I2CEN = 1, et mon compilateur se plaint l'espace entre les I2C1 et CONLbits jetons.

Répondre

5

Vous n'allez pas ajouter le niveau de macro correctement, comme je le vois. L'idiome habituel est de définir un wrapper qui ne fait que transmettre l'argument. De cette façon, si l'argument lui-même est une macro, il sera étendu avant d'être transmis à la macro qui est enveloppé:

#define I2C_MODULE_ENABLE__(x_) \ 
    I2C##x_##CONLbits.I2CEN = 1 

#define I2C_MODULE_ENABLE(x_) \ 
    I2C_MODULE_ENABLE__(x_) 

je pris la liberté de renommer votre paramètre macro, car les identificateurs avec les traits de soulignement sont définis comme réservé pour la mise en œuvre, je pense qu'il est préférable d'être sûr que désolé.


Pour résoudre votre problème de l'espace je partirais avec le niveau proverbiale d'indirection, et utiliser une fonction comme macro pour générer le jeton de préfixe correct, et le transmettre deux niveaux pour vous assurer qu'il est étendu correctement :

#define I2Cx__(x_) I2C##x_ 
#define I2C_MODULE_ENABLE__(IC_) \ 
    IC_##CONLbits.I2CEN = 1 
#define I2C_MODULE_ENABLE_(IC_) \ 
    I2C_MODULE_ENABLE__(IC_) 
#define I2C_MODULE_ENABLE(x_) \ 
    I2C_MODULE_ENABLE_(I2Cx__(x_)) 

voir vivre here

l'ensemble shtick est de vous assurer que le préprocesseur voit et produit des jetons valides à chaque étape. Ce qui peut être un peu fatigant.

+0

Cela ne résout pas vraiment le problème/réponds à la question. – melpomene

+0

@melpomene - J'y suis finalement arrivé. J'ai eu du mal à vérifier l'exemple de code sur mon compilateur de nuage préféré :) – StoryTeller

+0

Cela est toujours codé en dur pour utiliser 'CONLbits'. – melpomene