¿Cómo funcionan internamente los especificadores de formato?

Considerar:

int x=0xdeadbeef; char c=x; printf("%x",c); 

La salida es ffffffef . ¿Cómo? ¿Por qué NO es 000000ef ?

Un entero de 32 bits no cabe dentro de un carácter de 8 bits, por lo tanto, char c=x; es lo mismo que c=0xef .

Luego, aparentemente, char está firmado en su comstackdor y 0xef es más grande que 127, por lo que se convierte a algún valor negativo, -17.

Cuando se pasa a printf , el valor negativo char se promueve a int , el signo se conserva (esto se denomina “promoción de argumento predeterminado” y es utilizado por todas las funciones variadic). La representación de complemento a dos de 32 bits -17 es ffffffef . Con %x usas el especificador de formato incorrecto; printf espera unsigned int . Intenta mostrar el número firmado como sin firmar.

Puedes corregir el error reemplazando char con uint8_t .

En general, este código es muy cuestionable, ya que se basa en muchos comportamientos mal especificados. No debe desbordar enteros con signo, no debe usar char para almacenar valores, debe hacer un esfuerzo para usar los especificadores de formato correctos.

Esto es menos una cuestión de “cómo funcionan los especificadores de formato” y más un “cómo funciona char “.

Un char sin ningún otro tipo de información puede ser un valor firmado o sin firmar, el cual depende del comstackdor. Si desea una firma específica, debe usar caracteres unsigned char o caracteres con signed char .

La instrucción de formato %x espera un int sin signo, por lo que (esencialmente) convertirá el char primero en un int, luego lo interpretará como un int sin signo. Si su carácter está firmado, se ampliará cuando se convierta en un int y es por eso que obtiene el valor que está viendo.