¿Por qué los estándares C o C ++ no definen explícitamente a char como firmado o sin signo?

int main() { char c = 0xff; bool b = 0xff == c; // Under most C/C++ compilers' default options, b is FALSE!!! } 

Ni el estándar C ni C ++ especifican char como firmado o sin signo, está definido por la implementación.

¿Por qué el estándar C / C ++ no define explícitamente char como firmado o sin signo para evitar usos indebidos peligrosos como el código anterior?

Razones históricas, en su mayoría.

Las expresiones de tipo char se promueven a int en la mayoría de los contextos (porque muchas CPU no tienen operaciones aritméticas de 8 bits). En algunos sistemas, la extensión de letreros es la forma más eficiente de hacerlo, lo que char firma de char simples.

Por otro lado, el juego de caracteres EBCDIC tiene caracteres básicos con el conjunto de bits de orden alto (es decir, caracteres con valores de 128 o mayores); en las plataformas EBCDIC, char prácticamente no tiene firma.

El ANSI C Rationale (para el estándar de 1989) no tiene mucho que decir sobre el tema; la sección 3.1.2.5 dice:

Se especifican tres tipos de caracteres: signed , simple y unsigned . Un char simple puede representarse como firmado o no, dependiendo de la implementación, como en la práctica anterior. El tipo signed char se introdujo para poner a disposición un tipo entero con signo de un byte en los sistemas que implementan el carácter simple como sin signo. Por razones de simetría, la palabra clave signed está permitida como parte del nombre de tipo de otros tipos integrales.

Retrocediendo aún más, una versión temprana del Manual de referencia de C de 1975 dice:

Un objeto char se puede usar en cualquier lugar donde pueda estar int . En todos los casos, el char se convierte en un int al propagar su signo a través de los 8 bits superiores del entero resultante. Esto es consistente con la representación del complemento de los dos utilizada tanto para los caracteres como para los enteros. (Sin embargo, la característica de propagación de signos desaparece en otras implementaciones).

Esta descripción es más específica de la implementación que lo que vemos en documentos posteriores, pero reconoce que char puede estar firmado o no. En las “otras implementaciones” en las que “la propagación del signo desaparece”, la promoción de un objeto char a int tendría cero extensión de la representación de 8 bits, esencialmente tratándola como una cantidad sin firmar de 8 bits. (El idioma aún no tenía la palabra clave signed o unsigned ).

El predecesor inmediato de C era un lenguaje llamado B. B era un lenguaje sin teclas, por lo que la pregunta de que char estuviera firmado o no firmado no se aplicaba. Para obtener más información sobre la historia temprana de C, consulte la página de inicio de Dennis Ritchie, que ahora se mudó aquí .

En cuanto a lo que está sucediendo en su código (aplicando reglas C modernas):

 char c = 0xff; bool b = 0xff == c; 

Si el char simple no está firmado, la inicialización de c establece en (char)0xff , que se compara con 0xff en la segunda línea. Pero si se firma un char simple, entonces 0xff (una expresión de tipo int ) se convierte en char , pero como 0xff supera a CHAR_MAX (asumiendo CHAR_BIT==8 ), el resultado está definido por la implementación . En la mayoría de las implementaciones, el resultado es -1 . En la comparación 0xff == c , ambos operandos se convierten en int , por lo que es equivalente a 0xff == -1 , o 255 == -1 , que es por supuesto falso.

Otra cosa importante a tener en cuenta es que el unsigned char , el unsigned char y el signed char (simple) son tres tipos distintos. char tiene la misma representación que unsigned char o signed char ; está definido por la implementación, cuál es. (Por otro lado, signed int e int son dos nombres para el mismo tipo, unsigned int es un tipo distinto. (Excepto que, solo para agregar a la frivolidad, su implementación define si un campo de bit declarado como plain int está firmado) o sin firmar.))

Sí, todo está un poco desordenado, y estoy seguro de que se hubiera definido de manera diferente si C se estuviera diseñando desde cero hoy. Pero cada revisión del lenguaje C ha tenido que evitar romper (demasiado) el código existente y, en menor medida, las implementaciones existentes.

char al principio está destinado a almacenar caracteres, por lo tanto, firmar o no firmar no es importante. Lo que realmente importa es cómo realizar las matemáticas de forma eficiente. Así que depende del sistema, el comstackdor elegirá lo que sea más apropiado

Antes de ARMv4, ARM no tenía soporte nativo para cargar halfwords y bytes firmados. Para cargar un byte con signo, tenía que LDRB y luego firmar extender el valor (LSL arriba y luego volver a ASR). Esto es doloroso así que char no está firmado por defecto.

https://stackoverflow.com/a/6532932/995714