C: ¿por qué imprimir un carácter nulo con% s imprime “(nulo)”?

¿Por qué al imprimir un carácter nulo (‘\ 0’, 0) con% s se imprime la cadena “(nulo)” en realidad?

Me gusta este código:

char null_byte = '\0'; printf("null_byte: %s\n", null_byte); 

…impresión:

 null_byte: (null) 

… e incluso se ejecuta sin errores en Valgrind, todo lo que recibo es la advertencia del comstackdor warning: format '%s' expects argument of type 'char *', but argument 2 has type 'int' [-Wformat] (nota: Estoy usando gcc 4.6.3 en Ubuntu de 32 bits)

Es un comportamiento indefinido, pero sucede que en su implementación:

  • El valor int de 0 que pasa se lee con %s como un puntero nulo
  • el manejo de %s por printf tiene un código de caso especial para identificar un puntero nulo e imprimir (null) .

Ninguno de los dos es requerido por la norma. La parte que se requiere [*], es que un char utilizado en varargs se pasa como un int .

[*] Bueno, es necesario dado que en tu implementación todos los valores de char pueden representarse como int . Si estuvieras en una implementación divertida donde char no tiene firma y tiene el mismo ancho que int , se pasaría como unsigned int . Creo que la implementación divertida se ajustaría a la norma.

Bueno, para empezar, lo estás haciendo mal. '\0' es un carácter y debe imprimirse con %c y no con %s . No sé si esto es intencional para fines de experimentación.

El valor binario real de \0 es, bueno, 0. Está intentando convertir el valor 0 en un puntero char * , lo que daría como resultado una falla y una referencia no válidas. Su comstackdor está impidiendo que con un tratamiento especial del valor %s .

Valgrind no lo detectará porque se ejecuta en el binario resultante, no en el código fuente (en su lugar, necesitará un analizador estático). Como el comstackdor ya ha convertido esa llamada en un texto seguro de “puntero nulo”, valgrind no verá nada mal.

null_byte contiene 0. Cuando usa% s en printf, está intentando imprimir una cadena, que es una dirección de un carácter (un carácter *). Lo que hace en su código, es que está pasando la dirección 0 (NULL) como la dirección de su cadena, por lo que la salida es nula. El comstackdor te advirtió que pasaste el tipo incorrecto al modificador% s. intente printf (“null_byte:% s \ n”, & null_byte);

Su statement printf está intentando imprimir una cadena y, por lo tanto, interpreta el valor null_bye como un char * que tiene el valor nulo. Presta atención a la advertencia. O bien hacer esto

 printf("null_byte: %s\n", &null_byte); 

o esto

 printf("null_byte: %c\n", null_byte); 

Debido a que printf es variadic, las promociones de argumentos habituales se realizan en null_byte para que se promueva (lance) a int , valor 0 .

printf luego lee un puntero char * , y el int de 0 se interpreta como un puntero nulo. La biblioteca estándar de C tiene una función en la que las cadenas nulas se imprimen como (null) .