Quelle est la taille de la mémoire tampon minimale pour sprintf avec% g?
Question
Le problème consiste à répartir de manière statique un tampon suffisamment grand pour contenir une double imprimé, mis en forme avec g% à un maximum de précision. Cela semble être une tâche assez simple, bu, je vais avoir du mal. Le meilleur que je suis venu avec (en supposant que le nombre à imprimer est x)
char buf[1 + DBL_DIG + DBL_DIG + 1 + 1 + 1 + DBL_DIG + 1];
int len = sprintf(buf, "%.*g", DBL_DIG, x);
La macro DBL_DIG est de float.h, et apparemment il est censé indiquer la précision maximale pour le type double. Nous avons besoin:
- 1 octet pour un signe négatif
- assez d'octets pour saisir les chiffres significatifs
- au plus un char 'séparateur' (virgule, etc.) par chiffre
- 1 octet pour un point décimal
- 1 octet pour 'e'
- 1 octet pour le signe de l'exposant
- quelques octets pour l'exposant
- 1 octet pour le null de fuite écrit par sprintf.
J'utilise le nombre de chiffres significatifs comme une limite supérieure du nombre de chiffres dans l'exposant. Ai-je fait une erreur? Y at-il une meilleure solution? Devrais-je allouer 64, 128 ou 256 octets et espérer le meilleur?
La solution 4
Au lieu d'utiliser sprintf
, vous pouvez utiliser asprintf
. Cela alloue un buffer de la taille correcte pour l'adapter à votre chaîne.
Autres conseils
Vous ne pouvez pas pré-calculer la taille au moment de la compilation. Le formatter% g prend les paramètres régionaux en compte (pour le séparateur de 1000, etc. de) Voir http://linux.die.net/man/3/sprintf pour la description sur la façon de calculer la taille en toute sécurité.
Utilisez snprintf()
pour savoir combien de caractères dont vous avez besoin:
#include <float.h> /* DBL_DIG */
#include <stdio.h>
#include <stdlib.h>
int main(void) {
double x = rand() / (double)RAND_MAX;
char find_len[1];
int need_len;
char *buf;
need_len = snprintf(find_len, 1, "%.*g", DBL_DIG, x);
buf = malloc(need_len + 1);
if (buf) {
int used = sprintf(buf, "%.*g", DBL_DIG, x);
printf("need: %d; buf:[%s]; used:%d\n", need_len, buf, used);
free(buf);
}
return 0;
}
Vous avez besoin d'un compilateur C99 pour snprintf()
.
snprintf()
a été défini par la norme C99. Une mise en œuvre de C89 n'est pas nécessaire d'avoir snprintf()
défini, et si elle a comme une extension, il n'est pas nécessaire de « travailler » tel que décrit par la norme C99.
Deux choses:% g ne montre pas tous les chiffres représentables,% g montre un beau-pour-homme arrondi résultat. Vous pouvez spécifier la précision en utilisant% f ou% e si vous voulez un résultat différent.
Ne jamais utiliser sprintf () plutôt que d'utiliser snprintf (). Dans ton cas:
int len = snprintf(buf, dimensionof(buf), "%.*f", DBL_DIG, x);
Dois-je arrondir juste à 64, 128 ou 256 et espérer pour le mieux?
Oui, il suffit de faire que -.-