Impresión del valor de char declarado en C

Entiendo que la variable de carácter se mantiene desde (firmado) -128 a 127 y (sin signo) 0 a 255

char x; x = 128; printf("%d\n", x); 

pero como funciona? ¿Por qué obtengo -128 para x ?

printf es una función variable, que solo proporciona un tipo exacto para el primer argumento.
Eso significa que las promociones predeterminadas se aplican a los siguientes argumentos, por lo que todos los enteros de rango menor que int se promueven a int o unsigned int , y todos los valores flotantes de rango más pequeño se promueven al double .

Si su implementación tiene CHAR_BIT de 8, y se firma un char simple y tiene una implementación de complemento 2s complaciente, obtendrá

128 (literal) a -128 ( char / signed char ) a -128 ( int ) impresos como int => -128

Si se cumplen todas las condiciones enumeradas pero la implementación del complemento obligatorio 2, se obtiene una señal o algún valor definido por la implementación.

De lo contrario, obtienes una salida de 128, porque 128 se ajusta en char / unsigned char .

Cotización estándar para el caso 2 (Gracias a Matt por descubrir la referencia correcta ):

6.3.1.3 Enteros firmados y sin firmar

1 Cuando un valor con tipo entero se convierte en otro tipo entero distinto de _Bool, si el valor puede representarse por el nuevo tipo, no se modifica.
2 De lo contrario, si el nuevo tipo no tiene firma, el valor se convierte sumndo o restando repetidamente uno más que el valor máximo que se puede representar en el nuevo tipo hasta que el valor esté en el rango del nuevo tipo.60)
3 De lo contrario, el nuevo tipo está firmado y el valor no puede representarse en él; o bien el resultado está definido por la implementación o se genera una señal definida por la implementación.

Todo esto no tiene nada que ver con funciones variadas, promociones de argumentos predeterminados, etc.

Suponiendo que su sistema tiene caracteres firmados, entonces x = 128; está realizando una asignación fuera de rango. El comportamiento de esto está definido por la implementación ; lo que significa que el comstackdor puede elegir una acción pero debe documentar lo que hace (y, por lo tanto, hacerlo de manera confiable). Esta acción está permitida para incluir el aumento de una señal.

El comportamiento habitual de los comstackdores modernos para la asignación fuera de rango es truncar la representación del valor para que se ajuste al tipo de destino.

En representación binaria, 128 es 000....00010000000 . Al truncarlo en un carácter firmado, se obtiene el carácter firmado de la representación binaria 10000000 . En la representación del complemento a dos , que es utilizada por todos los sistemas C modernos para números negativos, esta es la representación del valor -128 . (Para la curiosidad histórica: en el complemento de uno es -127 , y en magnitud de signo, es -0 que puede ser una representación de trampa y, por lo tanto, generar una señal).

Finalmente, printf imprime con precisión el valor de este carácter de -128 . El modificador %d funciona para char debido a las promociones de argumentos predeterminadas y los hechos que INT_MIN <= CHAR_MIN e INT_MAX >= CHAR_MAX . este comportamiento está garantizado, excepto en los sistemas que tienen caracteres simples sin firmar y sizeof(int)==1 (que sí existen, pero lo sabrías si estuvieras en uno).

Veamos la representación binaria de 128 cuando se almacena en 8 bits:

1000 0000

Y ahora veamos la representación binaria de -128 cuando se almacena en 8 bits:

1000 0000

El estándar para char con su configuración actual parece ser un signed char (tenga en cuenta que no está en el estándar c, mire aquí si no me cree) y, por lo tanto, cuando asigne el valor de 128 a x usted asignándole el valor 1000 0000 y, por lo tanto, cuando lo comstack e imprime, está imprimiendo el valor firmado de esa representación binaria (es decir, -128 ).

Resulta que mi entorno es el mismo en el supuesto de que char está signed char realidad. Como era de esperar, si lanzo x para ser un personaje unsigned char , obtengo la salida esperada de 128 :

 #include  #include  int main() { char x; x = 128; printf("%d %d\n", x, (unsigned char)x); return 0; } 

Me da la salida de -128 128

¡Espero que esto ayude!