Comment envelopper printf() dans une fonction ou une macro?
Cela sonne un peu comme une question d'entrevue,mais est en fait un problème pratique.
Je suis en train de travailler avec une plate-forme intégrée, et disponible seulement les équivalents de ces fonctions:
- printf()
- snprintf()
En outre, le printf() mise en œuvre (et la signature) est susceptible de changer dans un avenir proche, de sorte que les appels doivent résider dans un module séparé, afin d'être facile à migrer plus tard.
Compte tenu de ces, puis-je envelopper la journalisation des appels à une fonction ou une macro? Le but est que mon code source des appels THAT_MACRO("Number of bunnies: %d", numBunnies);
en mille endroits, mais les appels à des fonctions ci-dessus sont vus seulement dans un seul endroit.
Compilateur: arm-gcc-std=c99
- Est-ce que votre prise en charge du compilateur variadic des macros?
- Quel compilateur restrictions sont en place? Si cela doit fonctionner sur une version de C avant de C99, il sera difficile à accomplir de façon portable comme une macro.
- J'ai pensé WHYT? commentaires a été bloqué ces jours-ci?
Vous devez vous connecter pour publier un commentaire.
Puisque vous pouvez utiliser des C99, j'avais de l'envelopper dans un variadic macro:
puisque vous n'avez pas de dire que vous avez
vprintf
ou quelque chose comme ça. Si vous avez quelque chose comme ça, vous pouvez l'envelopper dans une fonction comme Sergey L a fournis dans sa réponse.Edit:
Ci-dessus TM_PRINTF ne fonctionne pas avec un vide VA_ARGS liste.
Au moins dans GCC, il est possible d'écrire:
Les deux ## signes supprimer pour supprimer l'excès de virgule devant eux si
__VA_ARGS__
est vide.TM_PRINTF("Starting ei-oh!");
rendementserror: expected expression before ')' token
. Sans la chaîne de format argument, il fonctionne. Ne variadic les arguments doivent être non nul dans nombre?f_
feraitTM_PRINTF()
admissibles. Si les cordes étaient dans le code, le compilateur puisse se plaindre plus tard à propos de à propos deprintf()
qui ne correspond pas à sa fonction de signature. C'est mieux de faire le compilateur se plaindreTM_PRINTF
dans ce cas, puisque c'est le plus visible....
transmettre à__VA_ARGS__
?...
notation dans la#define
liste des paramètres et généralement__VA_ARGS__
dans le texte de remplacement. Le préprocesseur C (surtout avant C99) n'est pas aussi sophistiqué que les autres langues, à peine plus qu'un simple remplacement de texte. Dans ce cas, il faut faire plus que du simple texte de remplacement, il faut que ça en mémoire tampon jusqu'tous les jetons lorsque la macro est exécutée. Par exemple, dans l'invocationTM_PRINTF(foo, bar, baz)
le préprocesseur définit une variable de remplacementf_
pour le jetonfoo
et__VA_ARGS__
pour les jetonsbar
,,
etbaz
.gcc -std=c99
) sinon ça ne marche pas. Cygwin doit s'il a C99 soutien.Il y a 2 façons de le faire:
Variadric macro
fonction qui transmet
va_args
Il y a aussi des
vsnprintf
,vfprintf
et tout ce que vous pouvez penser,stdio
.#define THAT_MACRO printf
travail?Si vous pouvez vivre avec le fait d'avoir à placer l'appel en deux parenthèses, vous pouvez le faire comme ceci:
Puis l'utiliser:
Cela fonctionne puisque, dès le préprocesseur point de vue, l'ensemble de la liste des arguments devient une macro argument, qui est substitué avec de la parenthèse.
C'est mieux que de simples faire
Car il vous permet de définir ça:
Cela va "manger" la macro arguments, ils ne seront jamais partie du code compilé.
Mise à JOUR De cours en C99 cette technique est obsolète, il suffit d'utiliser un variadic macro et d'être heureux.
THAT_MACRO
aurez besoin des doubles parenthèses, même avec un seul argument des appels, par exempleTHAT_MACRO(("Foo Bar"))
. - Avec l'amour, un pauvre C89 programmeur de plusieurs années plus tard.La
##
jeton permettre l'utilisationTM_PRINTF("aaa");
Cela fonctionne comme ceci:
Il définit la macro paramétrable PRINTF accepter (jusqu'à) infini arguments, puis pré-traite de
PRINTF(...)
àprintf(__VA_ARGS__)
.__VA_ARGS__
est utilisé dans paramétré les définitions de macros pour désigner les arguments (cause vous ne pouvez pas le nom de l'infini arguments, pouvez-vous?).Limitée de la bibliothèque? Système embarqué? Besoin d'autant de la performance que possible? Pas de problème!
Comme démontré dans cette réponse à cette question, vous pouvez utiliser le langage d'assemblage pour l'envelopper d'une fonction qui n'accepte pas VA_LIST dans ceux qui le font, la mise en œuvre de votre propre vprintf à peu de frais!
Alors que cela fonctionne, et presque à coup sûr la performance ainsi que l'abstraction que vous voulez, je voudrais juste vous recommandons d'obtenir une plus pleine de fonctionnalités de la bibliothèque standard, peut-être par le découpage de pièces de uClibc. Une telle solution est sûrement le plus portable et le plus utile de répondre que d'utiliser de l'assemblée, sauf si vous avez absolument besoin de chaque cycle.
C'est pourquoi de tels projets existent, après tout.