c++ - significa - ¿Cuándo es uint8_t ≠ unsigned char?
uint8_t use (3)
¿En qué tipo de sistema
uint8_t
puede definirse legalmente como un tipo distinto de ununsigned char
?
En resumen, uint8_t
solo puede definirse legalmente en sistemas donde CHAR_BIT
es 8. Es una unidad direccionable con exactamente 8 bits de valor y sin bits de relleno.
En detalle, CHAR_BIT
define el ancho de las unidades direccionables más pequeñas, y uint8_t
no puede tener bits de relleno; solo puede existir cuando la unidad direccionable más pequeña tiene exactamente 8 bits de ancho. Si CHAR_BIT
es 8, uint8_t
se puede definir mediante una definición de tipo para cualquier tipo de entero sin signo de 8 bits que no tenga bits de relleno.
Esto es lo que dice el borrador estándar de C11 (n1570.pdf):
5.2.4.2.1 Tamaños de los tipos enteros 1 Los valores que figuran a continuación se reemplazarán por expresiones constantes adecuadas para su uso en las directivas de preprocesamiento #if. ... Sus valores definidos por la implementación serán iguales o mayores en magnitud (valor absoluto) a los mostrados, con el mismo signo.
-- number of bits for smallest object that is not a bit-field (byte) CHAR_BIT 8
Por lo tanto, los objetos más pequeños deben contener exactamente los bits CHAR_BIT.
6.5.3.4 Los operadores sizeof y _Alignof
...
4 Cuando se aplica sizeof a un operando que tiene el tipo char, unsigned char, o signed char, (o una versión calificada del mismo), el resultado es 1. ...
Por lo tanto, esas son (algunas de) las unidades direccionables más pequeñas. Obviamente, int8_t
y uint8_t
también pueden considerarse unidades direccionables más pequeñas, siempre que existan.
7.20.1.1 Tipos de enteros de ancho exacto
1 El nombre de typedef intN_t designa un tipo entero con signo con ancho N, sin bits de relleno y una representación de complemento a dos. Por lo tanto, int8_t denota un tipo entero con signo con un ancho de exactamente 8 bits.
2 El nombre typedef uintN_t designa un tipo entero sin signo con ancho N y sin bits de relleno. Por lo tanto, uint24_t denota un tipo entero sin signo con un ancho de exactamente 24 bits.
3 Estos tipos son opcionales. Sin embargo, si una implementación proporciona tipos de enteros con anchos de 8, 16, 32 o 64 bits, sin bits de relleno y (para los tipos con signo) que tienen una representación de complemento a dos, se definirán los nombres de typedef correspondientes.
El énfasis en " Estos tipos son opcionales " es mío. Espero que esto haya sido útil :)
Según C y C ++, CHAR_BIT >= 8
.
Pero siempre que CHAR_BIT > 8
, uint8_t
ni siquiera puede representarse como 8 bits.
Debe ser más grande, porque CHAR_BIT
es el número mínimo de bits para cualquier tipo de datos en el sistema.
¿En qué tipo de sistema uint8_t
puede definirse legalmente como un tipo distinto de un unsigned char
?
(Si la respuesta es diferente para C y C ++, me gustaría saber ambas cosas).
Si existe, uint8_t
siempre debe tener el mismo ancho que el unsigned char
. Sin embargo, no es necesario que sea del mismo tipo; puede ser un tipo entero extendido distinto. Tampoco es necesario que tenga la misma representación que el unsigned char
; por ejemplo, los bits se podrían interpretar en el orden opuesto. Este es un ejemplo tonto, pero tiene más sentido para int8_t
, donde los caracteres con signed char
pueden ser complementos o de magnitud de signo, mientras que int8_t
debe ser dos complementos.
Una "ventaja" adicional de usar un tipo de entero extendido no-char para uint8_t
incluso en sistemas "normales" son las reglas de alias de C. Los tipos de caracteres pueden alias cualquier cosa, lo que impide que el compilador optimice en gran medida las funciones que utilizan los punteros de caracteres y los punteros a otros tipos, a menos que la palabra clave de restrict
se haya aplicado bien. Sin embargo, incluso si uint8_t
tiene exactamente el mismo tamaño y representación que el unsigned char
, si la implementación lo convirtió en un tipo distinto, sin caracteres, las reglas de alias no se aplicarían a él, y el compilador podría asumir que los objetos de los tipos uint8_t
e int
, por ejemplo, nunca se puede alias.
Una posibilidad que nadie ha mencionado hasta ahora: si CHAR_BIT==8
y un char
no calificado están sin firmar, lo cual está en algunas ABI, entonces uint8_t
podría ser un typedef para char
lugar de un unsigned char
. Esto importa al menos en la medida en que afecte a la opción de sobrecarga (y su gemelo malvado, nombre mangling), es decir, si tuviera foo(char)
y foo(unsigned char)
en el alcance, llamar a foo
con un argumento de tipo uint8_t
preferiría foo(char)
en tal sistema.