¿Snprintf siempre es nulo terminando el búfer de destino?
En otras palabras, ¿es esto suficiente?
char dst[10];
snprintf(dst, sizeof (dst), "blah %s", somestr);
¿O tienes que hacer así, si alguna es lo suficientemente larga?
char dst[10];
somestr[sizeof (dst) - 1] = '\0';
snprintf(dst, sizeof (dst) - 1, "blah %s", somestr);
Estoy interesado tanto en lo que dice el estándar como en lo que podría hacer alguna libc popular que no es un comportamiento estándar.
Respuestas:
Como establecen las otras respuestas: Debería :
Así que todo lo que tienes que tener cuidado es no pasarle un búfer 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,históricamente solo tenía una función llamadasnprintf
sino que_snprintf
(observe el subrayado inicial) que no agrega un nulo final. Aquí están los documentos (VS 2012, ~~ VS 2013):http://msdn.microsoft.com/en-us/library/2ts7cx93%28v=vs.110%29.aspx
Visual Studio 2015 (VC14) aparentemente introdujo la
snprintf
función de conformidad , pero la heredada con el guión bajo inicial y el comportamiento de terminación no nula todavía está ahí:fuente
_snprintf
que eliminasnprintf
silenciosamente una característica de seguridad clave y permite que la cadena no tenga terminación nula?template <size_t size> int _snprintf_s(char (&buffer)[size], size_t count, const char *format [, argument] ...);
y también debo mencionar que esto sucede solo con el indicador de compilación / GS (Comprobación de seguridad). Esa función conoce el tamaño, la cuenta y la longitud.Según la página de manual de snprintf (3).
Entonces, sí, no es necesario terminar si el tamaño> = 1.
fuente
De acuerdo con el estándar C, a menos que el tamaño del búfer sea 0
vsnprintf()
ysnprintf()
null termine su salida.Por lo tanto, si necesita saber qué tamaño de búfer asignar, use un tamaño de cero y luego puede usar un puntero nulo como destino. Tenga en cuenta que me vinculé a las páginas POSIX, pero estas dicen explícitamente que no se pretende que haya ninguna divergencia entre Standard C y POSIX donde cubren el mismo terreno:
Tenga cuidado con la versión de Microsoft de
vsnprintf()
. Definitivamente se comporta de manera 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 finalice su salida en condiciones de error, mientras que la versión C estándar lo hace.Tenga en cuenta también las respuestas a ¿Utiliza las funciones seguras de TR 24731? (consulte MSDN para obtener la versión de Microsoft de
vsprintf_s()
) y la solución Mac para conocer las alternativas seguras a las funciones inseguras de la biblioteca estándar de C?fuente
Algunas versiones anteriores de SunOS hicieron cosas raras con snprintf y es posible que no hayan terminado con NUL la salida y tengan valores de retorno que no coincidan con lo que todos los demás estaban haciendo, pero cualquier cosa que se haya lanzado en los últimos 10 años ha estado haciendo lo que C99 dice.
fuente
La ambigüedad comienza en el propio estándar C. Tanto C99 como C11 tienen una descripción de
snprintf
función idéntica . Aquí está la descripción de C99:Por un lado la sentencia
dice que
si (
s
apunta a una matriz de 3 caracteres y)n
es 3, se escribirán 2 caracteres y se descartarán los caracteres más allá del segundo ; entonces 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 a la pregunta original.
LA RESPUESTA:
Si la copia tiene lugar entre objetos que se superponen, el comportamiento es indefinido.
Si
n
es 0, entonces no se escribe nada en la salida; de locontrario, si no se encuentran errores de codificación, la salida SIEMPRE termina en nulo ( independientemente de si la salida encaja en la matriz de salida o no ; si no, algunos caracteres se descartan de manera que la salida matriz nunca se desborda), de lo
contrario (si se encuentran errores de codificación) la salida puede permanecer sin terminación nula .
Por otro lado
La última frase
da ambigüedad (o mi inglés no es lo suficientemente bueno). Puedo interpretar esta oración de al menos dos formas:
1. La salida termina en nulo si y solo si el valor devuelto no es negativo y es menor que
n
(lo que significa que si el valor devuelto no es menor quen
, es decir, la salida (incluida la terminando carácter nulo) no cabe en la matriz, 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, provoca malentendidos y largas discusiones. Es por eso que la última oración que describe la
snprintf
función necesita un cambio para eliminar cualquier ambigüedad (lo que da motivos para escribir una propuesta para el estándar de lenguaje C).El ejemplo de redacción no ambigua creo que se puede tomar de http://en.cppreference.com/w/c/io/fprintf (ver
4)
), gracias a @ "Martin Ba" por el enlace.Consulte también la pregunta " snprintf: ¿Existen propuestas / planes de C estándar para cambiar la descripción de esta función? ".
fuente