O que é o tamanho mínimo de tampão para sprintf com% g?
Pergunta
O problema é alocar estaticamente um tampão suficientemente grande para caber uma dupla impresso, formatado com% g a máxima precisão. Esta parece ser uma tarefa bastante simples, bu estou tendo problemas. O melhor que eu vim com (assumindo que o número a ser impresso é x) é
char buf[1 + DBL_DIG + DBL_DIG + 1 + 1 + 1 + DBL_DIG + 1];
int len = sprintf(buf, "%.*g", DBL_DIG, x);
A macro DBL_DIG é de float.h, e aparentemente é suposto para indicar a precisão máxima para o tipo de casal. Precisamos de:
- 1 byte para um sinal negativo
- bytes suficientes para capturar os dígitos significativos
- , no máximo, um char 'separador' (vírgula, etc.) por algarismos
- 1 byte para um ponto decimal
- 1 byte por 'e'
- 1 byte para o sinal no expoente
- alguns bytes para o expoente
- 1 byte para o nulo de arrasto escrito por sprintf.
Eu estou usando o número de dígitos significativos como um limite superior para o número de dígitos no expoente. Fiz todos os erros? Existe uma solução melhor? Devo apenas alocar 64, 128 ou 256 bytes e esperança para o melhor?
Solução 4
Em vez de usar sprintf
, você poderia usar asprintf
. Isso aloca um buffer do tamanho correto para caber sua string.
Outras dicas
Você não pode pré-calcular o tamanho em tempo de compilação. O formatador% g leva a localidade em conta (para o separador de 1000, etc.) Consulte http://linux.die.net/man/3/sprintf para uma descrição sobre como calcular o tamanho segurança.
Use snprintf()
para descobrir quantos caracteres que você precisa:
#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;
}
Você precisa de um compilador C99 para snprintf()
.
snprintf()
foi definida pela norma C99. implementação A C89 não é obrigado a ter snprintf()
definido, e se ele tem como uma extensão, não é necessária a "trabalhar" como descrito pelo C99 padrão.
Duas coisas:% g não mostra todos os dígitos representáveis,% G mostra um resultado arredondado agradável-para-humanos. Você pode especificar a precisão usando% f ou% e se você gostaria de um resultado diferente.
Nunca uso sprintf () ao invés de usar snprintf (). No seu caso:
int len = snprintf(buf, dimensionof(buf), "%.*f", DBL_DIG, x);
Eu deveria rodada até 64, 128, ou 256 e esperar o melhor?
Sim, basta fazer isso -.-