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 yunsigned
. Unchar
simple puede representarse como firmado o sin firmar, según la implementación, como en la práctica anterior. El tipo consigned 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 clavesigned
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 unint
. En todos los casos, elchar
se convierte a unint
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