¿Por qué se imprime 0 (cero) sin “0x” inicial con formato C printf “%#x”?

4 minutos de lectura

avatar de usuario
david poole

Antecedentes: tengo una serie de secuencias de comandos que analizan los archivos de registro en busca de números hexadecimales al encontrar el “0x” inicial. Nuestra biblioteca C integrada cambió a un nuevo printf. El nuevo printf es más compatible con los estándares que el anterior y mis scripts fallaron.

En una caja de Linux:

#include <stdio.h>
int main( void )
{
    printf( "%#010x\n", 0 );
    printf( "%#010x\n", 1 );
    return 0;
}

La salida (usando glibc) es:

0000000000
0x00000001

La salida en nuestro firmware fue:

0x00000000
0x00000001

Desde printf(3), en el carácter indicador ‘#’: “Para conversiones x y X, un resultado distinto de cero tiene la cadena “0x” (o “0X” para conversiones X) antepuesta”.

Soy curioso por qué. Sin buscar en los documentos de estándares C o comprar el almuerzo para los miembros del comité de estándares, ¿por qué no un 0x inicial en un argumento de valor cero?

  • Suposición salvaje: 0 es 0 independientemente de la base, por lo que no es necesario especificarlo.

    –Daniel Fischer

    14 de diciembre de 2011 a las 23:32

  • Vale la pena señalar que puede obtener el comportamiento de siempre incluyendo un líder 0x escribiendo "0x%08x"mientras que el comportamiento descrito estándar sería más complicado de obtener de una biblioteca que siempre incluido el líder 0x. ¿Quizás el comité de estándares estaba optimizando para un caso más difícil de obtener de otra manera, en lugar del caso absolutamente más común? (Por supuesto, no puedes cambiar "%#10x" para "0x%8x"pero entonces, es difícil imaginar a alguien que quiera ver 0x0 sin relleno con ceros).

    – ruakh

    14 de diciembre de 2011 a las 23:36

  • No hay mención de esto en el C89 Justificación (HTML) o en el Justificación C99 (PDF).

    –Keith Thompson

    15 de diciembre de 2011 a las 0:06

avatar de usuario
Jukka Suomela

El estándar parece estar escrito de esta manera:

  • %#x y %#o intente garantizar que la salida se pueda analizar correctamente usando strtol con base = 0.

  • En estos casos, el # bandera agrega tan pocos caracteres adicionales como posible. Por ejemplo, 0 se imprime como 0 porque no hay necesidad de agregar el extra 0x. Esto tiene mucho sentido si lo haces no especifique el ancho de campo mínimo y el relleno 0.

  • Si quisieras agregar 0x siempre, a menudo podría simplemente escribir algo como 0x%x. Por lo tanto %#x parecería ser útil solamente en esos casos especiales en los que realmente querer el manejo especial de 0. Pero el antependiente de 0x no funciona bien con los especificadores de ancho de campo predeterminados, por ejemplo) 0x%12xestá justificado a la derecha con espacios en blanco entre el 0x y los dígitos hexadecimales, lo que es poco probable que sea lo que se busca en ese caso. Para este caso, se requeriría un pase preparatorio adicional con sprintf, por lo que una cadena hexadecimal como "0x2ac2" puede ser un espacio en blanco justificado a la derecha con algo como printf( "%12s", hexstr); Afortunadamente justificando con 0 en lugar de espacios usando algo como printf( "0x%012x", hexstr); funciona como se esperaba produciendo dígitos hexadecimales válidos para un analizador.

Ahora el camino %#x está especificado para trabajar tiene mucho sentido de forma aislada. Y la forma en que algo como %010x está especificado para trabajar tiene mucho sentido de forma aislada. Estás combinando estos dos modificadores y el resultado final es, posiblemente, extraño. Para otra aplicación, como la generación automática de código C ordenado para inicializar tablas, tener 0, en vez de 0x0 no es un problema

Pero no hay necesidad de combinar %#x y %010x. Podrías simplemente escribir 0x%08x para hacer lo que quieras

  • Y después de publicar la respuesta, noté que @ruakh ya había dado esencialmente la misma información en un comentario. Disculpas.

    – Jukka Suomela

    15 de diciembre de 2011 a las 0:00


  • +1. No hay necesidad de disculparse. Las respuestas son mejores que los comentarios. Publiqué mis pensamientos como un comentario, en lugar de una respuesta, porque sabía que no podían estar completos; pero su respuesta es mucho más completa y tiene mucho sentido.

    – ruakh

    15 de diciembre de 2011 a las 0:48

  • ¡Tanto la respuesta como los comentarios son apreciados! La idea de ser compatible con strtol tiene sentido. Ahora es el momento de cambiar una gran cantidad de código a 0x% 08x.

    –David Poole

    15 de diciembre de 2011 a las 13:42

  • ¿Por qué no 1 tener este comportamiento también? Es tan inequívoco como 0. No hay necesidad de agregar el extra 0x.

    – Burhan Alí

    11 de enero de 2013 a las 16:59

¿Ha sido útil esta solución?

Esta web utiliza cookies propias y de terceros para su correcto funcionamiento y para fines analíticos y para mostrarte publicidad relacionada con sus preferencias en base a un perfil elaborado a partir de tus hábitos de navegación. Al hacer clic en el botón Aceptar, acepta el uso de estas tecnologías y el procesamiento de tus datos para estos propósitos. Configurar y más información
Privacidad