Cela ressemble un peu à une question d'entrevue, mais c'est en fait un problème pratique.
Je travaille avec une plate-forme embarquée et ne dispose que des équivalents de ces fonctions:
De plus, l'implémentation (et la signature) de printf () est susceptible de changer dans un avenir proche, donc les appels à celle-ci doivent résider dans un module séparé, afin d'être facile à migrer plus tard.
Dans ces conditions, puis-je encapsuler les appels de journalisation dans une fonction ou une macro? Le but est que mon code source appelle THAT_MACRO("Number of bunnies: %d", numBunnies);
à mille endroits, mais les appels aux fonctions ci-dessus ne sont visibles qu'à un seul endroit.
Compilateur: arm-gcc -std = c99
Puisque vous pouvez utiliser C99, je l'envelopperais dans une macro variadique :
#define TM_PRINTF(f_, ...) printf((f_), __VA_ARGS__)
#define TM_SNPRINTF(s_, sz_, f_, ...) snprintf((s_), (sz_), (f_), __VA_ARGS__)
puisque vous n'avez pas dit 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 fourni dans sa réponse.
Le TM_PRINTF ci-dessus ne fonctionne pas avec une liste VA_ARGS vide. Au moins dans GCC, il est possible d'écrire:
#define TM_PRINTF(f_, ...) printf((f_), ##__VA_ARGS__)
Les deux signes ## remove suppriment l'excès de virgule devant eux si __VA_ARGS__
est vide.
Il y a 2 façons de procéder:
Macro variadrique
#define my_printf(...) printf(__VA_ARGS__)
fonction qui transmet va_args
#include <stdarg.h>
#include <stdio.h>
void my_printf(const char *fmt, ...) {
va_list args;
va_start(args, fmt);
vprintf(fmt, args);
va_end(args);
}
Il y a aussi vsnprintf
, vfprintf
et tout ce que vous pouvez penser dans stdio
.
Si vous pouvez vivre avec avoir à encapsuler l'appel entre deux parenthèses, vous pouvez le faire comme ceci:
#define THAT_MACRO(pargs) printf pargs
Ensuite, utilisez-le:
THAT_MACRO(("This is a string: %s\n", "foo"));
^
|
OMG
Cela fonctionne car du point de vue du préprocesseur, la liste entière des arguments devient un argument macro, qui est remplacé par la parenthèse.
C'est mieux que de le faire simplement
#define THAT_MACRO printf
Puisqu'il vous permet de le définir:
#define THAT_MACRO(pargs) /* nothing */
Cela "dévorera" les arguments des macros, ils ne feront jamais partie du code compilé.
UPDATE Bien sûr, en C99, cette technique est obsolète, utilisez simplement une macro variadique et soyez heureux.
#define TM_PRINTF(f_, ...) printf((f_), ##__VA_ARGS__)
Le jeton ##
Activera l'utilisation TM_PRINTF("aaa");
#define PRINTF(...) printf(__VA_ARGS__)
Cela fonctionne comme ceci:
Il définit la macro paramétrée PRINTF pour accepter (jusqu'à) des arguments infinis, puis la prétraite de PRINTF(...)
à printf(__VA_ARGS__)
. __VA_ARGS__
Est utilisé dans les définitions de macro paramétrées pour désigner les arguments donnés (car vous ne pouvez pas nommer des arguments infinis, n'est-ce pas?).
Bibliothèque limitée? Système embarqué? Besoin d'autant de performances que possible? Aucun problème!
Comme démontré dans cette réponse à cette question , vous pouvez utiliser le langage d'assemblage pour encapsuler des fonctions qui n'acceptent pas VA_LIST dans celles qui le font, implémentant votre propre vprintf à peu de frais!
Bien que cela fonctionne, et se traduise presque certainement par les performances et l'abstraction que vous souhaitez, je vous recommanderais simplement d'obtenir une bibliothèque standard plus riche en fonctionnalités, peut-être en découpant des parties de Clibc . Une telle solution est sûrement une réponse plus portable et globale plus utile que d'utiliser Assembly, à moins que vous n'ayez absolument besoin de chaque cycle.
C'est pourquoi de tels projets existent, après tout.