sprintf snprintf pro plus mplab c posix libc

snprintf - strcat



Es snprintf() SIEMPRE nulo terminando? (5)

Algunas versiones anteriores de SunOS hacían cosas raras con snprintf y podían no haber terminado con NUL la salida y tenían valores de retorno que no coincidían con lo que hacían los demás, pero todo lo que se ha lanzado en los últimos 10 años ha estado haciendo lo que C99 dice.

¿Snprintf siempre es nulo al finalizar el buffer de destino?

En otras palabras, ¿esto es suficiente?

char dst[10]; snprintf(dst, sizeof (dst), "blah %s", somestr);

o tienes que hacer esto, si somestr es lo suficientemente largo?

char dst[10]; somestr[sizeof (dst) - 1] = ''/0''; snprintf(dst, sizeof (dst) - 1, "blah %s", somestr);

Me interesa tanto lo que dice la norma como lo que una libc popular podría hacer, que no es un comportamiento estándar.


Como las otras respuestas establecen: should :

should ... Escribe los resultados en un búfer de cadena de caracteres. (...) terminará con un carácter nulo, a menos que buf_size sea cero.

Entonces, todo lo que tiene que tener cuidado es que no le pase un buffer de tamaño cero, porque (obviamente) no puede escribir un cero en "ninguna parte".

Sin embargo, tenga en cuenta que la biblioteca de Microsoft no tiene una función llamada snprintf sino que históricamente solo tenía una función llamada _snprintf (nota del guión bajo) que no agrega un nulo de terminación. Aquí están los documentos (VS 2012, ~~ VS 2013):

http://msdn.microsoft.com/en-us/library/2ts7cx93%28v=vs.110%29.aspx

Valor de retorno

Permita que len sea la longitud de la cadena de datos formateada (sin incluir el nulo de terminación). len y count están en bytes para _snprintf, caracteres anchos para _snwprintf.

  • Si len <count, los caracteres len se almacenan en el búfer, se agrega un terminador nulo y se devuelve len.

  • Si len = count, los caracteres len se almacenan en buffer, no se agrega null-terminator y len se devuelve.

  • Si len> count, los caracteres de conteo se almacenan en el búfer, no se agrega un terminador nulo y se devuelve un valor negativo.

(...)

Visual Studio 2015 (VC14) aparentemente introdujo la función snprintf conformes, pero la versión heredada con el subrayado inicial y el comportamiento de terminación no nula sigue ahí:

La función snprintf trunca la salida cuando len es mayor o igual que el conteo, colocando un terminador nulo en el buffer[count-1] . (...)

Para todas las funciones distintas de snprintf , si len = count, los caracteres len se almacenan en el búfer, no se agrega null-terminator , (...)


De acuerdo con el estándar C, a menos que el tamaño del buffer sea 0, vsnprintf() y snprintf() null termina su salida.

La función snprintf() será equivalente a sprintf() , con la adición del argumento n que establece el tamaño del búfer al que se refiere s. Si n es cero, no se escribirá nada y s puede ser un puntero nulo. De lo contrario, los bytes de salida más allá de n-1st se descartarán en lugar de escribirse en la matriz, y se escribirá un byte nulo al final de los bytes realmente escritos en la matriz.

Por lo tanto, si necesita saber qué tan grande es un búfer para asignar, use un tamaño de cero, y luego puede usar un puntero nulo como destino. Tenga en cuenta que me he vinculado a las páginas de POSIX, pero éstas explícitamente dicen que no se pretende que exista ninguna divergencia entre el estándar C y el POSIX, donde cubren el mismo terreno:

La funcionalidad descrita en esta página de referencia está alineada con el estándar ISO C. Cualquier conflicto entre los requisitos descritos aquí y el estándar ISO C es involuntario. Este volumen de POSIX.1-2008 difiere al estándar ISO C.

Tenga cuidado con la versión de Microsoft de vsnprintf() . Definitivamente se comporta de forma diferente a la versión C estándar cuando no hay suficiente espacio en el búfer (devuelve -1 donde la función estándar devuelve la longitud requerida). No está del todo claro que la versión nula de Microsoft termine su salida en condiciones de error, mientras que la versión C estándar sí lo hace.

Tenga en cuenta también las respuestas a ¿Utiliza las funciones de seguridad TR 24731? (ver MSDN para la versión de Microsoft de vsprintf_s() ) y la solución de Mac para las alternativas seguras a las inseguras funciones de biblioteca estándar de C?


De acuerdo con snprintf (3) página de manual.

Las funciones snprintf() y vsnprintf() escriben en la mayoría de los bytes de size (incluido el byte nulo final (''/ 0'')) en str .

Entonces, sí, no es necesario terminar si size> = 1.


La ambigüedad comienza desde el Estándar C mismo. Tanto C99 como C11 tienen una descripción idéntica de la función snprintf . Aquí está la descripción de C99:

7.19.6.5 La función snprintf
Sinopsis
1 #include <stdio.h> int snprintf(char * restrict s, size_t n, const char * restrict format, ...);
Descripción
2 La función snprintf es equivalente a fprintf , excepto que la salida se escribe en una matriz (especificada por el argumento s ) en lugar de en una secuencia. Si n es cero, no se escribe nada, y s puede ser un puntero nulo. De lo contrario, los caracteres de salida más allá de la n-1 st se descartan en lugar de escribirse en la matriz, y se escribe un carácter nulo al final de los caracteres escritos en la matriz. Si la copia se lleva a cabo entre objetos que se superponen, el comportamiento no está definido.
Devoluciones
3 La función snprintf devuelve el número de caracteres que se han escrito si n fuera lo suficientemente grande, sin contar el carácter nulo de terminación, o un valor negativo si se produjo un error de codificación. Por lo tanto, la salida terminada en nulo se ha escrito completamente si y solo si el valor devuelto es no negativo y menor que n .

Por un lado, la oración

De lo contrario, los caracteres de salida más allá de la n-1 st se descartan en lugar de escribirse en la matriz, y se escribe un carácter nulo al final de los caracteres escritos en la matriz.

dice que
si (la s apunta a una matriz de 3 caracteres de largo, y) n es 3, se escribirán 2 caracteres y se descartarán los caracteres que estén más allá de la segunda ; luego el carácter nulo se escribe después de esos 2 (y el carácter nulo será el tercer carácter escrito) .

Y esto creo que responde la pregunta original.
LA RESPUESTA:
Si la copia se lleva a cabo entre objetos que se superponen, el comportamiento no está definido.
Si n es 0, entonces no se escribe nada en la salida
de lo contrario, si no se encuentran errores de codificación, la salida SIEMPRE es nula ( independientemente de si la salida encaja en la matriz de salida o no ; si no, algunos caracteres se descartan de forma que la matriz de salida nunca se sobrevuela),
de lo contrario (si se encuentran errores de codificación) la salida puede permanecer no terminada en nulo .

Por otra parte
La última oración

Por lo tanto, la salida terminada en nulo se ha escrito completamente si y solo si el valor devuelto es no negativo y menor que n

da ambigüedad (o mi inglés no es lo suficientemente bueno). Puedo interpretar esta oración al menos de dos maneras:
1. La salida tiene terminación nula si y solo si el valor devuelto es no negativo y menor que n (lo que significa que si el valor devuelto no es menor que n , es decir, la salida (incluido el carácter nulo de terminación) no cabe en array, entonces la salida no es terminada en nulo ).
2. La salida está completa (no se han descartado caracteres) si y solo si el valor devuelto es no negativo y menor que n .

Creo que la interpretación 1 anterior contradice LA RESPUESTA, causa malentendidos y largas discusiones. Es por eso que la última oración que describe la función snprintf necesita un cambio para eliminar cualquier ambigüedad (lo que da motivos para escribir una Propuesta en el estándar de lenguaje C).
El ejemplo de una redacción no ambigua creo que se puede tomar de should (ver 4) ), gracias a @ "Martin Ba" para el enlace.

Véase también la pregunta " snprintf: ¿Hay alguna propuesta estándar de C / planes para cambiar la descripción de esta función? ".