La création de C formaté des chaînes de caractères (ne pas imprimer)
J'ai une fonction qui accepte une chaîne de caractères, c'est:
void log_out(char *);
À l'appeler, j'ai besoin de créer une chaîne formatée, à la volée, comme:
int i = 1;
log_out("some text %d", i);
Comment puis-je le faire en C ANSI?
Seulement, depuis sprintf()
retourne un int, ce qui signifie que je dois écrire au moins 3 commandes, comme:
char *s;
sprintf(s, "%d\t%d", ix, iy);
log_out(s);
Tout moyen de raccourcir ce?
- J'ai confiance que le prototype de fonction est vraiment: extern void log_out(const char *, ...); parce que si elle ne l'est pas, l'appel est erronée (trop d'arguments). Il convient de prendre un pointeur const car il n'y a aucune raison pour log_out() pour modifier la chaîne. Bien sûr, vous pourriez dire que vous souhaitez passer une seule chaîne à la fonction mais ne le peuvent pas. Une option consiste alors à écrire un varargs version de la log_out() fonction.
Vous devez vous connecter pour publier un commentaire.
Utilisation sprintf.
Paramètres:
Exemple:
sprintf
la façon dont vous l'utiliserprintf
, la seule différence étant la première chaîne supplémentaire tampon argument. E. g.:printf("Hi, I've got %d apples\n", apples)
vssprintf(out_string, "Hi, I've got %d apples\n", apples)
. Si vous ne se soucient pas de l'ansi et vous êtes prêt à utiliser C99, utiliser snprintf:snprintf(out_string, out_length, "Hi, I've got %d apples\n", apples)
.Si vous avez une POSIX-2008 système conforme à l' (modernes de Linux), vous pouvez utiliser le coffre-fort et pratique
asprintf()
fonction: Ilmalloc()
assez de mémoire pour vous, vous n'avez pas besoin de vous soucier de la taille maximale de la chaîne. L'utiliser comme ceci:C'est le minimum d'effort, vous pouvez obtenir de construire la chaîne, de façon sécuritaire. Le
sprintf()
code que vous avez donné en question est profondément erronée:Il n'est pas alloué de mémoire derrière le pointeur. Vous êtes à la rédaction de la chaîne à un endroit aléatoire dans la mémoire!
Même si vous aviez écrit
vous être dans le pétrin, parce que vous ne pouvez pas connaître le numéro à mettre dans les parenthèses.
Même si l'on avait utilisé la "sécurité" variante
snprintf()
, vous courez toujours le danger que vos chaînes soit tronquée. Lors de l'écriture dans un fichier journal, qui est relativement mineur, mais il a le potentiel pour couper avec précision les informations qui auraient été utiles. Aussi, il va couper la fuite finale de caractère, le collage, la prochaine ligne de journal à la fin de votre vain écrite ligne.Si vous essayez d'utiliser une combinaison de
malloc()
etsnprintf()
pour produire comportement correct dans tous les cas, vous vous retrouvez avec environ deux fois plus de code que j'ai donné pourasprintf()
, et, fondamentalement, reprogrammer la fonctionnalité deasprintf()
.Si vous cherchez à offrir un wrapper de
log_out()
qui peut prendre unprintf()
paramètre de style de la liste elle-même, vous pouvez utiliser la variantevasprintf()
qui prend unva_list
comme argument. Ici est parfaitement sécurisé mise en place d'un wrapper:asprintf()
ne fait pas partie de la norme C 2011 qui ne font pas partie de la norme POSIX, même pas POSIX 2008 ou 2013. Il fait partie de TR 27431-2: voir utilisez-vous le TR 24731 " sûr " fonctions?Il me semble que vous voulez être en mesure de passer facilement d'une chaîne créée à l'aide de printf mise en forme de style de la fonction vous avez déjà qui prend une chaîne de caractères. Vous pouvez créer un wrapper de la fonction en utilisant
stdarg.h
installations etvsnprintf()
(qui peut ne pas être facilement disponibles, selon votre compilateur/plate-forme):Pour les plates-formes qui n'assurent pas une bonne mise en œuvre (ou la mise en œuvre) de la
snprintf()
de la famille des routines, j'ai utilisé avec succès près d'un public de domainesnprintf()
à partir de Holger Weiss.Si vous avez le code pour
log_out()
, de le réécrire. Très probablement, vous pouvez le faire:Si il y a des informations de journalisation supplémentaires nécessaires, qui peuvent être imprimées avant ou après le message indiqué. Cela permet d'économiser de l'allocation de mémoire et douteux des tailles de mémoire tampon et ainsi de suite et ainsi de suite. Vous avez probablement besoin d'initialiser
logfp
à zéro (pointeur nul) et vérifier si elle est nulle et ouvrez le fichier journal le cas échéant, mais le code existant dans leslog_out()
devrait s'en occuper, que de toute façon.L'avantage de cette solution est que vous pouvez simplement appeler ça comme si c'était une variante de
printf()
; en effet, c'est une variante mineure surprintf()
.Si vous n'avez pas le code pour
log_out()
, demandez-vous si vous pouvez la remplacer par une variante comme celui décrit ci-dessus. Si vous pouvez utiliser le même nom dépendra de votre application cadre et la source ultime de l'actuellog_out()
fonction. Si c'est dans le même fichier de l'objet comme un autre indispensable fonction, vous devez utiliser un nouveau nom. Si vous ne pouvez pas travailler sur la façon de reproduire exactement, vous devrez utiliser des variantes comme celles données dans d'autres réponses qui alloue une quantité appropriée de la mémoire.Évidemment, vous appelez maintenant la
log_out_wrapper()
au lieu delog_out()
- mais l'allocation de mémoire et ainsi de suite est effectuée qu'une fois. Je me réserve le droit d'être sur l'allocation de l'espace par une inutile octet - je n'ai pas vérifié si la longueur renvoyée parvsnprintf()
comprend la valeur null ou pas.Ne pas utiliser sprintf.
Elle déborde de votre Chaîne-Tampon et le plantage de votre Programme.
Toujours utiliser snprintf
Je n'ai pas fait cela, alors je vais juste à point à la bonne réponse.
C a des dispositions pour des fonctions non spécifié nombre d'opérandes, à l'aide de la
<stdarg.h>
en-tête. Vous pouvez définir votre fonction en tant quevoid log_out(const char *fmt, ...);
, et obtenir leva_list
l'intérieur de la fonction. Ensuite, vous pouvez allouer de la mémoire et de l'appelvsprintf()
avec la mémoire allouée, le format, etva_list
.Alternativement, vous pouvez utiliser cette fonction pour écrire une fonction analogue à
sprintf()
qui permettrait d'allouer de la mémoire et de retour de la chaîne mise en forme, générant plus ou moins comme ci-dessus. Ce serait une fuite de mémoire, mais si vous êtes juste de vous déconnecter, il ne peut pas d'importance.http://www.gnu.org/software/hello/manual/libc/Variable-Arguments-Output.html donne l'exemple suivant pour imprimer sur stderr. Vous pouvez la modifier pour utiliser votre fonction de journal à la place:
Au lieu de vfprintf vous aurez besoin d'utiliser vsprintf où vous en avez besoin pour fournir un tampon à imprimer en.