¿Cuál es la ventaja de usar uint8_t
más unsigned char
en C?
Sé que en casi todos los sistemas uint8_t
es solo una definición de tipo unsigned char
, entonces, ¿por qué usarlo?
¿Cuál es la ventaja de usar uint8_t
más unsigned char
en C?
Sé que en casi todos los sistemas uint8_t
es solo una definición de tipo unsigned char
, entonces, ¿por qué usarlo?
Respuestas:
Documenta su intención: almacenará números pequeños, en lugar de un personaje.
También se ve mejor si está usando otros typedefs como uint16_t
o int32_t
.
unsigned char
o signed char
documenta la intención también, ya que sin adornos char
es lo que muestra que estás trabajando con personajes.
unsigned
era unsigned int
por definición?
char
parece implicar un carácter, mientras que en el contexto de una cadena UTF8, puede ser solo un byte de un carácter multibyte. El uso de uint8_t podría dejar en claro que no se debe esperar un carácter en cada posición; en otras palabras, cada elemento de la cadena / matriz es un entero arbitrario sobre el que no se deben hacer suposiciones semánticas. Por supuesto, todos los programadores de C lo saben, pero puede empujar a los principiantes a hacer las preguntas correctas.
Solo para ser pedante, algunos sistemas pueden no tener un tipo de 8 bits. De acuerdo con Wikipedia :
Se requiere una implementación para definir tipos enteros de ancho exacto para N = 8, 16, 32 o 64 si y solo si tiene algún tipo que cumpla con los requisitos. No es necesario definirlos para ninguna otra N, incluso si admite los tipos apropiados.
Por uint8_t
lo tanto, no se garantiza que exista, aunque lo hará para todas las plataformas donde 8 bits = 1 byte. Algunas plataformas integradas pueden ser diferentes, pero eso se está volviendo muy raro. Algunos sistemas pueden definir char
tipos de 16 bits, en cuyo caso probablemente no habrá ningún tipo de 8 bits.
Aparte de ese problema (menor), la respuesta de @Mark Ransom es la mejor en mi opinión. Utilice el que muestre más claramente para qué está utilizando los datos.
Además, supongo que usted quiso decir uint8_t
(el tipo de definición estándar de C99 proporcionado en el stdint.h
encabezado) en lugar de uint_8
(no forma parte de ningún estándar).
uint8_t
(o escribirlo para eso). Esto se debe a que el tipo de 8 bits tendría bits no utilizados en la representación de almacenamiento, que uint8_t
no debe tener.
typedef unsigned integer type uint8_t; // optional
Entonces, en esencia, no se necesita una biblioteca conforme estándar C ++ para definir uint8_t (ver el comentario // opcional )
El punto es escribir código independiente de la implementación. unsigned char
no se garantiza que sea un tipo de 8 bits. uint8_t
es (si está disponible).
sizeof(unsigned char)
regresará 1
por 1 byte. pero si un sistema char e int son del mismo tamaño, por ejemplo, de 16 bits sizeof(int)
, también volverá1
Como dijiste, " casi todos los sistemas".
char
es probablemente uno de los menos propensos a cambiar, pero una vez que comience a usar uint16_t
y amigos, usar las uint8_t
mezclas mejor, e incluso puede ser parte de un estándar de codificación.
En mi experiencia, hay dos lugares donde queremos usar uint8_t para significar 8 bits (y uint16_t, etc.) y donde podemos tener campos de menos de 8 bits. Ambos lugares son donde el espacio es importante y, a menudo, necesitamos mirar un volcado sin procesar de los datos al depurar y debemos poder determinar rápidamente qué representa.
El primero está en los protocolos de RF, especialmente en los sistemas de banda estrecha. En este entorno, es posible que necesitemos empaquetar tanta información como podamos en un solo mensaje. El segundo es en el almacenamiento flash, donde podemos tener un espacio muy limitado (como en los sistemas integrados). En ambos casos, podemos usar una estructura de datos empaquetados en la que el compilador se encargará del empaque y desempaquetado por nosotros:
#pragma pack(1)
typedef struct {
uint8_t flag1:1;
uint8_t flag2:1;
padding1 reserved:6; /* not necessary but makes this struct more readable */
uint32_t sequence_no;
uint8_t data[8];
uint32_t crc32;
} s_mypacket __attribute__((packed));
#pragma pack()
El método que use depende de su compilador. Es posible que también deba admitir varios compiladores diferentes con los mismos archivos de encabezado. Esto sucede en sistemas integrados donde los dispositivos y servidores pueden ser completamente diferentes, por ejemplo, puede tener un dispositivo ARM que se comunica con un servidor Linux x86.
Hay algunas advertencias sobre el uso de estructuras empaquetadas. El mayor problema es que debe evitar desreferenciar la dirección de un miembro. En sistemas con palabras mutibyte alineadas, esto puede resultar en una excepción desalineada, y un coredump.
Algunas personas también se preocuparán por el rendimiento y argumentarán que el uso de estas estructuras empaquetadas ralentizará su sistema. Es cierto que, detrás de escena, el compilador agrega código para acceder a los miembros de datos no alineados. Puede ver eso mirando el código de ensamblaje en su IDE.
Pero dado que las estructuras empaquetadas son más útiles para la comunicación y el almacenamiento de datos, los datos se pueden extraer en una representación no empaquetada cuando se trabaja con ellos en la memoria. Normalmente no necesitamos trabajar con todo el paquete de datos en la memoria de todos modos.
Aquí hay una discusión relevante:
pragma pack (1) ni __attribute__ ((alineado (1))) funciona
¿El __attribute __ ((empaquetado)) / #pragma pack de gcc no es seguro?
http://solidsmoke.blogspot.ca/2010/07/woes-of-structure-packing-pragma-pack.html
Hay poco. Desde el punto de vista de la portabilidad, char
no puede ser menor que 8 bits, y nada puede ser menor que char
, por lo que si una implementación C dada tiene un tipo entero de 8 bits sin signo, será char
. Alternativamente, es posible que no tenga ninguno, en cuyo punto cualquier typedef
truco es discutible.
Podría usarse para documentar mejor su código en el sentido de que está claro que necesita bytes de 8 bits y nada más. Pero en la práctica, es una expectativa razonable prácticamente en cualquier lugar (hay plataformas DSP en las que no es cierto, pero las posibilidades de que su código se ejecute allí son escasas, y también podría equivocarse usando una afirmación estática en la parte superior de su programa en tal plataforma).
unsigned char
poder mantener valores entre 0 y 255. Si puedes hacerlo en 4 bits, no tengo ganas.
uint8_t
a la implementación. Me pregunto, ¿los compiladores para DSP con caracteres de 16 bits suelen implementarse uint8_t
o no?
#include <stdint.h>
, y usar uint8_t
. Si la plataforma lo tiene, se lo dará. Si la plataforma no lo tiene, su programa no se compilará, y la razón será clara y directa.
Eso es realmente importante, por ejemplo, cuando está escribiendo un analizador de red. los encabezados de paquetes se definen por la especificación del protocolo, no por la forma en que funciona el compilador C de una plataforma en particular.
En casi todos los sistemas he conocido uint8_t == unsigned char, pero esto no está garantizado por el estándar C. Si está intentando escribir código portátil y importa exactamente el tamaño de la memoria, use uint8_t. De lo contrario, use char sin firmar.
uint8_t
siempre coincide con el rango y el tamaño unsigned char
y el relleno (ninguno) cuando unsigned char
es de 8 bits. Cuando unsigned char
no es de 8 bits, uint8_t
no existe.
unsigned char
está 8 bits, se uint8_t
garantiza que sea una typedef
de la misma y no una typedef
de un tipo entero sin signo extendido ?
unsigned char/signed char/char
el tipo más pequeño, no más pequeño que 8 bits. unsigned char
No tiene relleno. Para uint8_t
ser, debe ser de 8 bits, sin relleno, debido a un tipo entero proporcionado por la implementación: que coincida con los requisitos mínimos de unsigned char
. En cuanto a "... garantizado para ser un typedef ..." parece una buena pregunta para publicar.