Comme mentionné dans plusieurs de mes questions précédentes, je travaille via K&R et je suis actuellement dans le préprocesseur. L'une des choses les plus intéressantes - quelque chose que je n'avais jamais su auparavant lors de mes précédentes tentatives pour apprendre C - est l' ##
opérateur du préprocesseur. Selon K&R:
L'opérateur de préprocesseur
##
fournit un moyen de concaténer des arguments réels pendant le développement de macro. Si un paramètre dans le texte de remplacement est adjacent à a##
, le paramètre est remplacé par l'argument réel, l'##
espace blanc et l'espace qui l'entoure sont supprimés et le résultat est à nouveau analysé. Par exemple, la macropaste
concatène ses deux arguments:
#define paste(front, back) front ## back
paste(name, 1)
crée ainsi le jetonname1
.
Comment et pourquoi quelqu'un utiliserait-il cela dans le monde réel? Quels sont des exemples pratiques de son utilisation et y a-t-il des pièges à considérer?
std::wstring BuildDate = WIDEN(__DATE__) L" " WIDEN(__TIME__);
et créer implicitement la chaîne entière à la fois.Une chose à savoir lorsque vous utilisez les opérateurs de prétraitement token-paste ('
##
') ou stringizing ('#
') est que vous devez utiliser un niveau supplémentaire d'indirection pour qu'ils fonctionnent correctement dans tous les cas.Si vous ne le faites pas et que les éléments passés à l'opérateur de collage de jetons sont eux-mêmes des macros, vous obtiendrez des résultats qui ne sont probablement pas ceux que vous souhaitez:
Le résultat:
la source
__LINE__
c'est un nom de macro spécial qui est remplacé par le préprocesseur avec le numéro de ligne actuel du fichier source.Voici un piège que j'ai rencontré lors de la mise à niveau vers une nouvelle version d'un compilateur:
L'utilisation inutile de l'opérateur de collage de jetons (
##
) n'est pas portable et peut générer des espaces, des avertissements ou des erreurs indésirables.Lorsque le résultat de l'opérateur de collage de jetons n'est pas un jeton de préprocesseur valide, l'opérateur de collage de jetons est inutile et peut-être dangereux.
Par exemple, on peut essayer de créer des chaînes littérales au moment de la compilation en utilisant l'opérateur de collage de jetons:
Sur certains compilateurs, cela produira le résultat attendu:
Sur d'autres compilateurs, cela inclura des espaces non souhaités:
Les versions assez modernes de GCC (> = 3.3 ou plus) ne parviendront pas à compiler ce code:
La solution consiste à omettre l'opérateur de collage de jetons lors de la concaténation des jetons de préprocesseur en opérateurs C / C ++:
Le chapitre de la documentation GCC CPP sur la concaténation contient des informations plus utiles sur l'opérateur de collage de jetons.
la source
Ceci est utile dans toutes sortes de situations afin de ne pas vous répéter inutilement. Voici un exemple du code source d'Emacs. Nous aimerions charger un certain nombre de fonctions à partir d'une bibliothèque. La fonction "foo" doit être assignée à
fn_foo
, et ainsi de suite. Nous définissons la macro suivante:On peut alors l'utiliser:
L'avantage est de ne pas avoir à écrire les deux
fn_XpmFreeAttributes
et"XpmFreeAttributes"
(et de risquer de mal orthographier l'un d'entre eux).la source
Une question précédente sur Stack Overflow demandait une méthode fluide pour générer des représentations de chaîne pour les constantes d'énumération sans beaucoup de retaper sujettes aux erreurs.
Lien
Ma réponse à cette question a montré comment appliquer peu de magie de préprocesseur vous permet de définir votre énumération comme ceci (par exemple) ...;
... Avec l'avantage que l'expansion des macros ne définit pas seulement l'énumération (dans un fichier .h), elle définit également un tableau correspondant de chaînes (dans un fichier .c);
Le nom de la table de chaînes provient du collage du paramètre de macro (c'est-à-dire Color) dans StringTable à l'aide de l'opérateur ##. Les applications (astuces?) Comme celle-ci sont où les opérateurs # et ## sont inestimables.
la source
Vous pouvez utiliser le collage de jetons lorsque vous avez besoin de concaténer des paramètres de macro avec autre chose.
Il peut être utilisé pour les modèles:
Dans ce cas, LINKED_LIST (int) vous donnerait
De même, vous pouvez écrire un modèle de fonction pour le parcours de liste.
la source
Je l'utilise dans les programmes C pour aider à appliquer correctement les prototypes pour un ensemble de méthodes qui doivent se conformer à une sorte de convention d'appel. D'une certaine manière, cela peut être utilisé pour l'orientation de l'objet du pauvre en C droit:
se développe en quelque chose comme ceci:
Cela impose un paramétrage correct pour tous les objets «dérivés» lorsque vous faites:
ce qui précède dans vos fichiers d'en-tête, etc. Il est également utile pour la maintenance si vous souhaitez même modifier les définitions et / ou ajouter des méthodes aux "objets".
la source
SGlib utilise ## pour fondre les modèles en C. Comme il n'y a pas de surcharge de fonction, ## est utilisé pour coller le nom du type dans les noms des fonctions générées. Si j'avais un type de liste appelé list_t, alors j'obtiendrais des fonctions nommées comme sglib_list_t_concat, et ainsi de suite.
la source
Je l'utilise pour une assertion roulée à domicile sur un compilateur C non standard pour embarqué:
la source
##
?Je l'utilise pour ajouter des préfixes personnalisés aux variables définies par des macros. Donc quelque chose comme:
s'étend à:
la source
L'utilisation principale est lorsque vous avez une convention de dénomination et que vous souhaitez que votre macro tire parti de cette convention de dénomination. Peut-être avez-vous plusieurs familles de méthodes: image_create (), image_activate () et image_release () ainsi que file_create (), file_activate (), file_release () et mobile_create (), mobile_activate () et mobile_release ().
Vous pouvez écrire une macro pour gérer le cycle de vie des objets:
Bien sûr, une sorte de «version minimale des objets» n'est pas la seule sorte de convention de dénomination à laquelle cela s'applique - presque la grande majorité des conventions de dénomination utilisent une sous-chaîne commune pour former les noms. Cela pourrait moi des noms de fonction (comme ci-dessus), ou des noms de champs, des noms de variables ou presque tout le reste.
la source
Une utilisation importante dans WinCE:
Lors de la définition de la description du bit de registre, nous procédons comme suit:
Et tout en utilisant BITFMASK, utilisez simplement:
la source
C'est très utile pour la journalisation. Tu peux faire:
Ou, si votre compilateur ne prend pas en charge les fonctions et func :
Les «fonctions» ci-dessus enregistrent le message et montrent exactement quelle fonction a enregistré un message.
Ma syntaxe C ++ n'est peut-être pas tout à fait correcte.
la source