long float c int printf

float - Determinar el tamaño del búfer de sprintf, ¿cuál es el estándar?



printf php (7)

Algunos aquí están argumentando que este enfoque es excesivo, y para convertir las intenciones en cadenas, podría estar más inclinado a estar de acuerdo. Pero cuando no se puede encontrar un límite razonable para el tamaño de la cadena, he visto este enfoque utilizado y lo he usado yo mismo.

int size = snprintf(NULL, 0, "%d", 132); char * a = malloc(size + 1); sprintf(a, "%d", 132);

Voy a desglosar lo que está pasando aquí.

  1. En la primera línea, queremos determinar cuántos caracteres necesitamos. Los primeros 2 argumentos para snprintf indican que quiero escribir 0 caracteres del resultado en NULL . Cuando hacemos esto, snprintf no escribirá ningún carácter en ningún lugar, simplemente devolverá el número de caracteres que se habrían escrito. Esto es lo que queríamos.
  2. En la segunda línea, asignamos dinámicamente la memoria a un puntero de char . Asegúrese de agregar 1 al tamaño requerido (para el carácter de terminación /0 final).
  3. Ahora que hay suficiente memoria asignada al puntero de caracteres, podemos usar con seguridad sprintf para escribir el número entero en el indicador de caracteres.

Por supuesto puedes hacerlo más conciso si quieres.

char * a = malloc(snprintf(NULL, 0, "%d", 132) + 1); sprintf(a, "%d", 132);

A menos que este sea un programa "rápido y sucio", siempre debes asegurarte de liberar la memoria que malloc con malloc . Aquí es donde el enfoque dinámico se complica con C. Sin embargo, en mi humilde opinión, si no desea asignar grandes punteros de caracteres cuando la mayoría del tiempo solo va a usar una porción muy pequeña de ellos, entonces no creo este es un mal enfoque

Al convertir un int como este:

char a[256]; sprintf(a, "%d", 132);

¿Cuál es la mejor manera de determinar qué tan grande debería ser? Supongo que configurarlo manualmente está bien (como lo he visto usado en todas partes), pero ¿qué tan grande debe ser? ¿Cuál es el valor int más grande posible en un sistema de 32 bits, y hay alguna manera difícil de determinar eso sobre la marcha?


El número máximo posible de bits en un int es CHAR_BIT * sizeof(int) , y un dígito decimal "vale" al menos 3 bits, por lo que un límite superior suelto en el espacio requerido para un int arbitrario es (CHAR_BIT * sizeof(int) / 3) + 3 . Ese +3 es uno por el hecho de que redondeamos hacia abajo al dividir, uno por el signo, uno por el terminador nul.

Si por "en un sistema de 32 bits" quiere decir que sabe que int es de 32 bits, entonces necesita 12 bytes. 10 para los dígitos, uno para el signo, uno para el terminador nulo.

En su caso específico, donde el int a convertir es 132 , necesita 4 bytes. Badum, tish.

Cuando se pueden usar buffers de tamaño fijo con un límite razonable, son la opción más sencilla. No estoy tan humildemente afirmando que el límite anterior es razonable (13 bytes en lugar de 12 para 32 bits int , y 23 bytes en lugar de 21 para 64 bits int ). Pero para los casos difíciles, en C99 puede simplemente llamar a snprintf para obtener el tamaño, y luego malloc tanto. Eso es una exageración para un caso tan simple como este.


En primer lugar, sprintf es el diablo. En todo caso, use snprintf o, de lo contrario, corre el riesgo de destruir la memoria y bloquear la aplicación.

En cuanto al tamaño del búfer, es como todos los otros búferes: lo más pequeño posible, tan grande como sea necesario. En su caso, tiene un entero con signo, así que tome el mayor tamaño posible y siéntase libre de agregar un poco de relleno de seguridad. No hay "tamaño estándar".

Tampoco depende de qué sistema está ejecutando. Si define el búfer en la pila (como en su ejemplo), depende del tamaño de la pila. Si usted mismo creó el hilo, entonces determinó usted mismo el tamaño de la pila, para que conozca los límites. Si va a esperar una recursión o un seguimiento profundo de la pila, también necesita tener mucho cuidado.


Es bueno que te preocupe el tamaño del búfer. Para aplicar ese pensamiento en el código, usaría snprintf

snprintf( a, 256, "%d", 132 );

o

snprintf( a, sizeof( a ), "%d", 132 ); // when a is array, not pointer


Es posible hacer que la solución de Daniel Standage funcione para cualquier número de argumentos utilizando vsnprintf que está en C ++ 11 / C99.

int bufferSize(const char* format, ...) { va_list args; va_start(args, format); int result = vsnprintf(NULL, 0, format, args); va_end(args); return result + 1; // safe byte for /0 }

Como se especifica en la norma c99 , sección 7.19.6.12:

La función vsnprintf devuelve el número de caracteres que se habrían escrito si n fuera suficientemente grande, sin contar el carácter nulo de terminación, o un valor negativo si un
Se produjo un error de codificación.


Si está imprimiendo un entero simple, y nada más, hay una manera mucho más sencilla de determinar el tamaño del búfer de salida. Al menos computacionalmente más simple, el código es un poco obtuso:

char *text; text = malloc(val ? (int)log10((double)abs(val)) + (val < 0) + 2 : 2);

log10 (valor) devuelve el número de dígitos (menos uno) necesarios para almacenar un valor positivo distinto de cero en la base 10. Se desvía un poco de los carriles para números menores a uno, por lo que especificamos abs () y codificamos la lógica especial para cero (El operador ternario, test? truecase: falsecase). Agregue uno para el espacio para almacenar el signo de un número negativo (val <0), uno para compensar la diferencia de log10 y otro para el terminador nulo (para un total de 2), y acaba de calcular la cantidad exacta de espacio de almacenamiento requerido para un número dado, sin llamar a snprintf () o equivalentes dos veces para realizar el trabajo. Además, utiliza menos memoria, generalmente, de lo que INT_MAX requerirá.

Sin embargo, si necesita imprimir muchos números muy rápidamente, no se moleste en asignar el búfer INT_MAX y luego imprima en ese lugar repetidamente. Menos memoria es mejor.

También tenga en cuenta que es posible que no necesite realmente el (doble) en lugar de un (flotador). No me molesté en comprobarlo. Hacer eso de un lado a otro también puede ser un problema. YMMV en todo eso. Sin embargo, funciona muy bien para mí.


Veo que esta conversación tiene un par de años, pero la encontré al intentar encontrar una respuesta para MS VC ++ donde snprintf no se puede usar para encontrar el tamaño. Voy a publicar la respuesta que finalmente encontré en caso de que ayude a alguien más:

VC ++ tiene la función _scprintf específicamente para encontrar el número de caracteres necesarios.