imprimir formato especificadores bytes c printf format-specifiers nul

especificadores - Pasando byte nulo a través del especificador de formato en `printf`



formato de printf en c (4)

En resumen: %c significa imprimir un carácter, por lo que printf imprime el carácter NUL cuyo valor es 0. NUL es un carácter no imprimible. Así que solo podemos ver un espacio allí.

"Hello / 0, world" es una cadena literal, el resultado de strlen("Hello/0, world") es 5. Por lo tanto, printf imprimirá el resultado "Hello".

Puedes ver más en el sitio web cppreference: cadena literal

Un literal de cadena de caracteres es una secuencia de cero o más caracteres multibyte entre comillas dobles, como en "xyz". El carácter nulo (''/ 0'') siempre se añade al literal de cadena, por lo tanto, un literal de cadena "Hola" es un carácter constante [6] que contiene los caracteres ''H'', ''e'', ​​''l'', ''l'' , ''0'', y ''/ 0''. Si un literal de cadena tiene caracteres nulos incrustados, representa una matriz que contiene más de una cadena.

¿Por qué printf imprime un espacio en lugar de detenerse cuando uso el carácter NULO de la tabla ASCII? Esto es lo que quiero decir:

printf("Hello%c, world", 0); //Hello , world printf("Hello%c, world", ''/0''); //Hello , world

Solo cuando coloco el carácter de escape en la propia cadena, printf detiene la cadena:

printf("Hello/0, world"); //Hello

Intenté esto en Windows 8, Windows 10 (usando cygwin, MinGW, Netbeans, Code :: Blocks), XUbuntu, es lo mismo.

¿Dónde está el problema? Le pregunté a uno de mis amigos, pero él dijo que no tenía tal problema, que los tres ejemplos se ejecutaron de la misma manera.


Está tomando una dependencia en un detalle de implementación de printf (). La función de salida de terminal de bajo nivel requiere la longitud de la cadena como argumento. Hay dos formas para que printf () haga esto.

La forma algo obvia es primero formatear la cadena, luego usar strlen (). Ese es el que esperabas.

Pero eso es ineficiente porque requiere un doble paso a través del búfer de cadenas y la adición de 0. La otra forma de hacerlo es rastrear la longitud de la cadena con formato al sustituir los campos, simplemente incrementándola por cada carácter agregado. Dado que continúa pasando el% c, ahora obtendrá la mayor longitud que incluye todo el pasado% c. Lo que la función de terminal hace con el 0 incorporado es también un detalle de implementación, dado que no es un carácter imprimible. Verlo sustituido con un espacio no es infrecuente.

La mejor manera de hacer esto es no confiar en los detalles de la implementación.


printf("Hello/0, world"); utiliza su parámetro como una cadena C, por lo que lo descodifica hasta que encuentra un carácter NUL, por lo que se detiene justo después de /0 , ignorando lo que sigue.

printf("Hello%c, world", 0); descodifica su parámetro (hasta que encuentra dentro de él un carácter NUL - es decir, después de d ), mientras tanto encuentra un %c , por lo que lo reemplaza con el carácter dado como parámetro (cuyo código ASCII es NUL) y luego lo envía al terminal Un personaje de NUL, y luego continúa.

El manual de Printf dice:

Estas funciones escriben la salida bajo el control de una cadena de formato que especifica cómo se convierten los argumentos subsiguientes [...] para la salida.


printf("Hello%c, world", 0); //Hello , world printf("Hello%c, world", ''/0''); //Hello , world

En ambos casos, está intentando imprimir el valor de carácter correspondiente al código de carácter 0 , que no es un carácter imprimible. No he encontrado el capítulo y el verso en él, pero sospecho que el comportamiento de intentar imprimir un valor de carácter nulo no está especificado o tal vez incluso no definido. De cualquier manera, no esperaría que se tratara como un terminador de cadena en este caso.

printf("Hello/0, world"); //Hello

En este caso, el carácter nulo es parte de la constante de cadena y el compilador lo interpreta como un terminador de cadena.