uint8_t vs char sin signo

¿Cuál es la ventaja de usar uint8_t sobre unsigned char en C?

Sé que en casi todos los sistemas uint8_t es solo un typedef para unsigned char , entonces ¿para qué usarlo?

Documenta su intención: almacenará números pequeños, en lugar de un personaje.

También se ve mejor si está usando otros uint16_t como uint16_t o int32_t .

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 de 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 tanto, uint8_t 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 tipos de caracteres para ser de 16 bits, en cuyo caso probablemente no habrá un tipo de 8 bits de ningún tipo.

Aparte de ese problema (menor), la respuesta de @Mark Ransom es la mejor en mi opinión. Usa el que muestra más claramente para qué estás usando los datos.

Además, uint8_t que se refería a uint8_t (el typedef estándar de C99 provisto en el encabezado stdint.h ) en lugar de uint_8 (que no forma parte de ningún estándar).

El objective es escribir un código independiente de la implementación. unsigned char no garantiza que sea un tipo de 8 bits. uint8_t es.

Como dijiste, ” casi todos los sistemas”.

char es probablemente una de las menos probables de cambiar, pero una vez que comienzas a usar uint16_t y uint16_t amigos, usar uint8_t combina mejor, e incluso puede ser parte de un estándar de encoding.

En mi experiencia, hay dos lugares en los que 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 ver un volcado sin procesar de los datos cuando se depura y debemos poder determinar rápidamente lo que representa.

El primero es en protocolos de RF, especialmente en sistemas de banda estrecha. En este entorno, podemos necesitar empacar la mayor cantidad de información posible en un solo mensaje. El segundo es en almacenamiento flash donde podemos tener un espacio muy limitado (como en los sistemas integrados). En ambos casos, podemos utilizar una estructura de datos empaquetada en la que el comstackdor se encargará del embalaje y desembalaje para 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 uses depende de tu comstackdor. También es posible que necesite admitir varios comstackdores 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 comunique con un servidor Linux x86.

Hay algunas advertencias con el uso de estructuras empaquetadas. El mayor problema es que debes evitar eliminar la referencia de la dirección de un miembro. En sistemas con palabras alineadas mutibyte, esto puede dar como resultado 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 comstackdor agrega código para acceder a los miembros de datos no alineados. Puedes verlo mirando el código ensamblador en tu IDE.

Pero como 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 ella en la memoria. Normalmente, no es necesario que trabajemos con todo el paquete de datos en la memoria de todos modos.

Aquí hay una discusión relevante:

pragma pack (1) ni __attribute__ ((aligned (1))) funciona

¿El paquete __attribute __ ((packed)) / #pragma de gcc es inseguro?

http://solidsmoke.blogspot.ca/2010/07/woes-of-structure-packing-pragma-pack.html

Hay poco. Desde el punto de vista de portabilidad, char no puede tener menos de 8 bits, y nada puede ser más pequeño que char , por lo que si una implementación C dada tiene un tipo entero de 8 bits sin signo, será char . Alternativamente, puede no tener uno en absoluto, en cuyo punto cualquier truco typedef es discutible.

Podría usarse para documentar mejor su código en un sentido que está claro que requiere bytes de 8 bits allí y nada más. Pero en la práctica es una expectativa razonable prácticamente en cualquier parte (hay plataformas DSP en las que no es cierto, pero las posibilidades de que el código se ejecute allí son escasas, y podrías equivocarte usando una afirmación estática en la parte superior de tu progtwig en tal plataforma).

En casi todos los sistemas he encontrado uint8_t == char sin signo, pero esto no está garantizado por el estándar C. Si está tratando de escribir código portátil y es exactamente el tamaño de la memoria, use uint8_t. De lo contrario, use char sin signo.

Eso es realmente importante, por ejemplo, cuando escribe un analizador de red. los encabezados de los paquetes se definen por la especificación del protocolo, no por la forma en que funciona el comstackdor C de una plataforma en particular.