J'ai une fonction qui accepte une chaîne, c'est-à-dire:
void log_out(char *);
En l'appelant, je dois créer une chaîne formatée à la volée comme:
int i = 1;
log_out("some text %d", i);
Comment faire cela dans ANSI C?
Seulement, puisque sprintf()
renvoie un int, cela signifie que je dois écrire au moins 3 commandes, comme:
char *s;
sprintf(s, "%d\t%d", ix, iy);
log_out(s);
Un moyen de raccourcir cela?
Réponses:
Utilisez sprintf .
Paramètres:
Exemple:
la source
Si vous avez un système compatible POSIX-2008 (n'importe quel Linux moderne), vous pouvez utiliser la fonction sûre et pratique
asprintf()
: il auramalloc()
suffisamment de mémoire pour vous, vous n'avez pas à vous soucier de la taille maximale de la chaîne. Utilisez-le comme ceci:C'est l'effort minimum que vous pouvez obtenir pour construire la chaîne de manière sécurisée. Le
sprintf()
code que vous avez donné dans la question est profondément imparfait:Il n'y a pas de mémoire allouée derrière le pointeur. Vous écrivez la chaîne dans un emplacement aléatoire de la mémoire!
Même si tu avais écrit
vous seriez en grande difficulté, car vous ne pouvez pas savoir quel chiffre mettre entre parenthèses.
Même si vous aviez utilisé la variante "sûre"
snprintf()
, vous courriez toujours le risque que vos chaînes soient tronquées. Lors de l'écriture dans un fichier journal, c'est une préoccupation relativement mineure, mais elle a le potentiel de couper précisément les informations qui auraient été utiles. En outre, il coupera le caractère de fin de ligne de fin, collant la ligne de journal suivante à la fin de votre ligne écrite sans succès.Si vous essayez d'utiliser une combinaison de
malloc()
etsnprintf()
de produire un comportement correct dans tous les cas, vous vous retrouvez avec environ deux fois plus de code que ce que j'ai donnéasprintf()
et reprogrammez fondamentalement la fonctionnalité deasprintf()
.Si vous cherchez à fournir un wrapper
log_out()
qui peut prendre uneprintf()
liste de paramètres de style elle-même, vous pouvez utiliser la variantevasprintf()
qui prend ava_list
comme argument. Voici une implémentation parfaitement sûre d'un tel wrapper:la source
asprintf()
ne fait ni partie de la norme C 2011 ni partie de POSIX, pas même POSIX 2008 ou 2013. Cela fait partie de TR 27431-2: voir Utilisez-vous les fonctions «sûres» du TR 24731?Il me semble que vous voulez pouvoir facilement passer une chaîne créée à l'aide d'un formatage de style printf à la fonction que vous avez déjà qui prend une chaîne simple. Vous pouvez créer une fonction wrapper à l'aide des fonctionnalités
stdarg.h
etvsnprintf()
(qui peuvent ne pas être facilement disponibles, selon votre compilateur / plateforme):Pour les plates-formes qui ne fournissent pas une bonne implémentation (ou une implémentation) de la
snprintf()
famille de routines, j'ai utilisé avec succès un domaine presque publicsnprintf()
de Holger Weiss .la source
Si vous avez le code
log_out()
, réécrivez-le. Très probablement, vous pouvez faire:Si des informations de journalisation supplémentaires sont nécessaires, elles peuvent être imprimées avant ou après le message affiché. Cela permet d'économiser l'allocation de mémoire et les tailles de tampon douteuses et ainsi de suite. Vous devez probablement initialiser
logfp
à zéro (pointeur nul) et vérifier s'il est nul et ouvrir le fichier journal le cas échéant - mais le code existantlog_out()
devrait de toute façon s'occuper de cela.L'avantage de cette solution est que vous pouvez simplement l'appeler comme s'il s'agissait d'une variante de
printf()
; en effet, il s'agit d'une variante mineure surprintf()
.Si vous n'avez pas le code
log_out()
, demandez-vous si vous pouvez le remplacer par une variante telle que celle décrite ci-dessus. La possibilité d'utiliser le même nom dépendra de la structure de votre application et de la source ultime de lalog_out()
fonction actuelle . S'il se trouve dans le même fichier objet qu'une autre fonction indispensable, vous devrez utiliser un nouveau nom. Si vous ne parvenez pas à la répliquer exactement, vous devrez utiliser une variante comme celles données dans d'autres réponses qui allouent une quantité appropriée de mémoire.De toute évidence, vous appelez maintenant la
log_out_wrapper()
place delog_out()
- mais l'allocation de mémoire et ainsi de suite est effectuée une fois. Je me réserve le droit de surallouer de l'espace d'un octet inutile - je n'ai pas revérifié si la longueur renvoyée parvsnprintf()
inclut le null de fin ou non.la source
N'utilisez pas sprintf.
Il débordera votre String-Buffer et plantera votre programme.
Utilisez toujours snprintf
la source
Je ne l'ai pas fait, alors je vais simplement vous indiquer la bonne réponse.
C a des dispositions pour les fonctions qui prennent des nombres non spécifiés d'opérandes, en utilisant l'en-
<stdarg.h>
tête. Vous pouvez définir votre fonction commevoid log_out(const char *fmt, ...);
, et obtenir l'va_list
intérieur de la fonction. Ensuite, vous pouvez allouer de la mémoire et appelervsprintf()
avec la mémoire allouée, le format etva_list
.Vous pouvez également l'utiliser pour écrire une fonction analogue à
sprintf()
celle qui allouerait de la mémoire et retournerait la chaîne formatée, la générant plus ou moins comme ci-dessus. Ce serait une fuite de mémoire, mais si vous vous déconnectez, cela n'a peut-être pas d'importance.la source
http://www.gnu.org/software/hello/manual/libc/Variable-Arguments-Output.html donne l'exemple suivant pour imprimer sur stderr. Vous pouvez le modifier pour utiliser votre fonction de journal à la place:
Au lieu de vfprintf, vous devrez utiliser vsprintf où vous devez fournir un tampon adéquat pour imprimer.
la source