usar tipos sirve salida que para los funciones funcion formatos formato estandar especificadores entrada datos como c++ c types compiler-construction standards

tipos - ¿Por qué los estándares de C o C++ no definen explícitamente el carácter como firmado o sin signo?



scanf (2)

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

Ni el estándar C o C ++ especifican que el carácter como firmado o no esté firmado, está definido por la implementación.

¿Por qué el estándar C / C ++ no define explícitamente el carácter como firmado o no firmado para evitar usos incorrectos 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 (debido a que muchas CPU no tienen operaciones aritméticas de 8 bits). En algunos sistemas, la extensión de signo es la forma más eficiente de hacer esto, que se basa en hacer una firma simple.

Por otro lado, el conjunto de caracteres EBCDIC tiene caracteres básicos con el conjunto de bits de orden superior (es decir, caracteres con valores de 128 o más); En las plataformas EBCDIC, char tiene que estar sin firmar.

La justificación de ANSI C (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 , plano y unsigned . Un char simple puede representarse como firmado o sin firmar, según la implementación, como en la práctica anterior. El tipo con signed char se introdujo para hacer disponible un tipo entero con signo de un byte en aquellos sistemas que implementan el carácter simple como sin signo. Por razones de simetría, la palabra clave signed se permite como parte del nombre de tipo de otros tipos integrales.

Volviendo aún más lejos, una versión anterior del Manual de referencia de C de 1975 dice:

Un objeto char puede ser usado en cualquier lugar donde pueda estar un int . En todos los casos, el char se convierte a un int mediante la propagación de su signo a través de los 8 bits superiores del entero resultante. Esto es consistente con la representación complementaria 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 el char puede ser firmado o no. En las "otras implementaciones" en las que "la propagación de signos desaparece", la promoción de un objeto char a int tendría una representación de 8 bits de extensión cero, esencialmente tratándolo 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 tipografía, por lo que no se aplicó la cuestión de la firma o sin firma. Para obtener más información sobre la historia temprana de C, consulte la página de inicio del difunto Dennis Ritchie, que se encuentra aquí .

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

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

Si plain char no está firmado, entonces la inicialización de c establece en (char)0xff , que se compara igual a 0xff en la segunda línea. Pero si se firma simple char , entonces 0xff (una expresión de tipo int ) se convierte a char , pero como 0xff supera a CHAR_MAX (asumiendo que 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 a int , por lo que es equivalente a 0xff == -1 , o 255 == -1 , que por supuesto es falso.

Otra cosa importante a tener en cuenta es que los caracteres unsigned char , los caracteres con signed char y los caracteres (simples) 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, está definido por la implementación si un campo de bit declarado como int simple está firmado o sin firmar.))

Sí, todo es un poco complicado, y estoy seguro de que se definiría de manera diferente si C se diseñara 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 si está firmado o sin firmar no es importante. Lo que realmente importa es cómo realizar las matemáticas en char eficiente. Así que dependiendo del sistema, el compilador elegirá lo que sea más apropiado

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

¿Por qué los tipos sin firma son más eficientes en la CPU del brazo?

De hecho, muchos compiladores ARM todavía usan caracteres unsigned char de forma predeterminada, porque incluso si puede cargar un byte con extensión de signo en las ISA ARM modernas, esa instrucción es aún menos flexible que la versión con extensión cero

  • ¿el char está firmado o no firmado por defecto en iOS?
  • char está unsigned por defecto en Android NDK

Y la mayoría de los compiladores modernos también le permiten cambiar el carácter de char en lugar de usar la configuración predeterminada