Linkdd: Continue comme ça j'aime bien tes journeaux sur des techniques avancées du C
même si j'y comprend pas grand choses parceque je n'en ai pas (encore) besoin xD
En C l'utilisation de sprintf() ou snprintf() requiert une taille prédéfini pour dupliquer votre chaine. Chose que le développeur ne connait pas forcément, dut peut-être à une entrée utilisateur n'ayant pas de taille prédéfini que l'on inclu dans notre chaine.
Je me suis moi même posé sur le problème, et j'ai pu observer une fonction de la GLib assez intérréssante : g_strdup_printf()
Cette fonction a exactement la même syntaxe que printf() et le même comportement que strdup(). Donc aucun besoin de spécifier une taille. Cependant inclure une dépendance tel que la GLib pour uniquement résoudre ce problème, cela parrait assez fou ^^
Je me suis donc penché sur les sources de la GLib pour observer comment cette fonction était rédigé. J'ai pu constater qu'elle utilisait en réalité une autre fonction, de la LibC cette fois ci : asprintf() et vasprintf(). Deux fonctions qui sont certifié GNU.
Pour obtenir ses deux fonctions, voici la marche à suivre :
1 2 | #define _GNU_SOURCE #include <stdio.h> |
Et voila. Maintenant voyons la syntaxe de ses fonctions :
1 2 | int asprintf (char **_ptr, char *fmt, ...); int vasprintf (char **_ptr, char *fmt, va_list _varg); |
Il suffit donc de passer l'adresse du pointeur qui va contenir la chaine, et le reste commun à *printf()
Voici donc un exemple d'utilisation :
1 2 3 4 | char *string = NULL; asprintf (&string, "test 121 %d", 2); printf ("%s\\n", string); |
Donnera :
test 121 2
Etant pro-BSD, inclure une source GNU dans mon code me déplaisais quelque peu
Voici donc le code que j'ai rédigé pour ses deux fonctions :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 | int vasprintf (char **ptr, const char *fmt, va_list args) { int ret = 0; char tmp = 0; if (ptr == NULL) /* petite sécurité pour éviter les segfaults */ return 0; /* On récupère 1 caractère de notre chaine préformaté, * vsnprintf() va lire la chaine complète et retourner * le nombre de caractère lu, donc la taille de la chaine */ ret = vsnprintf (&tmp, 1, fmt, args); *ptr = malloc (ret * sizeof (char)); /* on alloue notre chaine avec la taille précédement récupéré */ /* on vérifie que l'allocation c'est faite correctement */ if (*ptr == NULL) return 0; /* et on duplique la chaine à l'aide de vsprintf() */ ret = vsprintf (*ptr, fmt, args); return ret; } /* Ici il suffit d'appeler vasprintf() qui fait tout le boulot */ int asprintf (char **ptr, const char *fmt, ...) { va_list args; int ret = 0; va_start (args, fmt); ret = vasprintf (ptr, fmt, args); va_end (args); return ret; } |
L'utilisation de ses deux fonctions est donc relativement simple, et surtout : portable
| Author | Message |
|---|---|
kido
|
|
Group : Member |
Linkdd: Continue comme ça j'aime bien tes journeaux sur des techniques avancées du C |