Pregunta

Aparte de %hn y %hhn (donde los h o hh especifica el tamaño de la punta-a objeto), lo que es el punto de los modificadores de h y hh para especificadores de formato printf?

Debido a los valores de promociones que son requeridos por la norma para ser aplicado para las funciones variadic, es imposible para pasar argumentos de char tipo o short (o cualquier firmado / unsigned variantes de los mismos) a printf.

Según 7.19.6.1 (7), el modificador de h:

específica es que un siguiente d, i, o, u, x, o X especí conversión fi er se aplica a una short int o unsigned short int argumento (argumento de la voluntad Se han promovido de acuerdo con las promociones de números enteros, pero su valor se basará ser convertido a corto int o corto unsigned int antes de la impresión); o que un siguiente n especí conversión fi er se aplica a un puntero a un corto argumento int.

Si el argumento era en realidad de short tipo o unsigned short, luego ascenso a int seguida de una parte posterior conversión a short o unsigned short producirá el mismo valor como la promoción a int sin espalda conversión. Así, por argumentos de short tipo o unsigned short, %d, %u, etc. debe dar resultados idénticos a %hd, %hu, etc. (y del mismo modo para los tipos de char y hh).

Por lo que yo puedo decir, la única situación en la que el modificador de h o hh podría ser útil es cuando el argumento se lo pasó un int fuera del rango de short o unsigned short, por ejemplo.

printf("%hu", 0x10000);

pero mi opinión es que pasa el tipo incorrecto como esto resulta en un comportamiento indefinido de todos modos, por lo que podría no esperar que imprimir 0.

Uno de los casos del mundo real que he visto es el código de la siguiente manera:

char c = 0xf0;
printf("%hhx", c);

en el que el autor espera que imprima f0 pesar de la aplicación que tiene un tipo char llanura que se firmó (en cuyo caso, printf("%x", c) imprimiría fffffff0 o similar). Sin embargo, se justifica esta expectativa?

(Nota: Lo que está pasando es que el tipo original char, que es ascendido a int y la espalda convertida a unsigned char en lugar de char, cambiando así el valor que se imprime, pero no la norma especifica este comportamiento, o se trata. un detalle de implementación de software que puede ser roto confía en?)

¿Fue útil?

Solución

Una posible razón: la simetría con el uso de estos modificadores en las funciones de entrada con formato? Sé que no sería estrictamente necesario, pero tal vez había visto valor para eso?

A pesar de que no mencionan la importancia de la simetría para el modificadores "HH" en el documento C99 Fundamento , el comité lo menciona como una consideración de por qué el '% p' ??indicador de conversión es compatible con fscanf() (a pesar de que no era nuevo para C99 - "% p" soporte se encuentra en C90):

se añadió la conversión de puntero de entrada con p% de C89, aunque obviamente arriesgado, por la simetría con fprintf.

En la sección sobre fprintf(), el documento justificación C99 hace discutir que "hh" se añadió, sino que simplemente se refiere al lector a la sección fscanf():

Se añadieron los modificadores de longitud% hh y% ll en C99 (ver §7.19.6.2).

Sé que es un hilo tenue, pero yo estoy especulando de todos modos, así que pensé que le daría cualquier argumento que pudiera haber.

Además, para completar, la "h" modificador estaba en el estándar original de C89 - presumiblemente sería allí, incluso si no era estrictamente necesario debido al uso generalizado existente, incluso si no podría haber sido un requisito técnico para utilizar el modificador.

Otros consejos

En el modo %...x, todos los valores se interpretan como sin signo. Por lo tanto, los números negativos se imprimen como sus conversiones sin firmar. En la aritmética de complemento a 2, que utilizan la mayoría de procesadores, no hay diferencia en los patrones de bit entre un número negativo firmado y su equivalente sin signo positivo, que se define por la aritmética de módulo (añadiendo el valor máximo para el campo más uno para el número negativo, de acuerdo a la norma C99). Las porciones de todo el código de depuración en software más propensos a usar hace %x- el supuesto silencio que la representación de bits de un valor negativo firmado y su reparto sin signo es el mismo, lo cual sólo es cierto en la máquina de complemento a 2.

La mecánica de este fundido son tales que las representaciones hexadecimales de valor siempre implican, posiblemente imprecisa, que un número ha sido mostrada en complemento a 2, con tal de que no golpeó una condición de borde de donde las diferentes representaciones de números enteros tienen diferentes rangos. Esto incluso es válido para representaciones aritméticas donde el valor 0 no se representa con el patrón binario de todos 0s.

A short negativo aparece como un unsigned long en hexadecimal será, por lo tanto, en cualquier máquina, se rellena con f, debido a la extensión de signo implícito en la promoción, que se imprimirá printf. El valor es el mismo, pero es verdaderamente engañoso visualmente en cuanto al tamaño del campo, lo que implica una cantidad significativa de rango que simplemente no está presente.

%hx trunca la representación que se muestra para evitar este relleno, tal y como se concluyó en su caso de uso en el mundo real.

El comportamiento de printf no está definida cuando se pasa un int fuera del rango de short que debe ser impreso como short, pero la aplicación más sencilla, con mucho, simplemente descarta el bit alto por una prima abatido, así que mientras que la especificación no lo hace < em> requieren cualquier comportamiento específico, casi cualquier aplicación en su sano juicio va a acaba de realizar el truncamiento. Hay por lo general mejores maneras de hacer eso, sin embargo.

Si no printf es rellenar los valores sin signo o mostrar representaciones de valores con signo, %h no es muy útil.

El único uso que puedo pensar es para el paso de una unsigned short o unsigned char y utilizando el indicador de conversión %x. No se puede utilizar simplemente un %x desnuda -. El valor puede ser promovido a int en lugar de unsigned int, y entonces usted tiene un comportamiento indefinido

Sus alternativas son a convertir explícitamente el argumento a unsigned; o para uso %hx / %hhx con un argumento desnudo.

Los argumentos variadic a printf() et al son promovidos automáticamente utilizando las conversiones por defecto, por lo que cualquier valores short o char son promovidos a int cuando se pasa a la función.

En ausencia de los h o hh modificadores, que tendría que enmascarar los valores pasados ??para obtener el comportamiento correcto de manera fiable. Con los modificadores, que ya no tiene que enmascarar los valores; la implementación printf() hace el trabajo correctamente.

En concreto, para el formato %hx, el código dentro printf() puede hacer algo como:

va_list args;
va_start(args, format);

...

int i = va_arg(args, int);
unsigned short s = (unsigned short)i;
...print s correctly, as 4 hex digits maximum
...even on a machine with 64-bit `int`!

Estoy asumiendo que alegremente short es una cantidad de 16 bits; el estándar en realidad no garantiza que, por supuesto.

I encontrado que es útil para evitar la proyección de al formatear caracteres sin signo a hex:

        sprintf_s(tmpBuf, 3, "%2.2hhx", *(CEKey + i));

Es un menor conveniencia de codificación, y se ve más limpio que varios moldes (OMI).

otro lugar que es muy práctico es el chequeo del tamaño snprintf. gcc7 añadió comprobación de tamaño cuando se utiliza snprintf por lo que este se producirá un error

char arr[4];
char x='r';
snprintf(arr,sizeof(arr),"%d",r);

lo que le obliga a utilizar carbón más grandes cuando se utiliza% d al dar formato a un char

aquí es una confirmación que muestra esas correcciones en lugar de aumentar el tamaño de matriz de caracteres cambiaron% d a% h. esta también dan descripción más exacta

https://github.com/Mellanox/libvma/commit/b5cb1e34a04b40427d195b14763e462a0a705d23 # diff-6258d0a11a435aa372068037fe161d24

Estoy de acuerdo con usted en que no es estrictamente necesario, y así por esa razón no es bueno en una función de biblioteca C:)

Puede ser que sea "buena" para la simetría de las diferentes banderas, pero es sobre todo contraproducente porque oculta la "conversión a int" regla.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top