uint8_t vs char unsigned

Qual è il vantaggio dell’uso di uint8_t sul unsigned char in C?

So che su quasi tutti i sistemi uint8_t è solo un typedef per il unsigned char , quindi perché usarlo?

Documenta il tuo intento: memorizzerai piccoli numeri, piuttosto che un personaggio.

Inoltre sembra più bello se stai usando altri uint16_t come uint16_t o int32_t .

Solo per essere pedante, alcuni sistemi potrebbero non avere un tipo a 8 bit. Secondo Wikipedia :

È richiesta un’implementazione per definire i tipi di interi a larghezza esatta per N = 8, 16, 32 o 64 se e solo se ha qualsiasi tipo che soddisfi i requisiti. Non è necessario definirli per nessun altro N, anche se supporta i tipi appropriati.

Quindi non è garantito che uint8_t esista, sebbene per tutte le piattaforms con 8 bit = 1 byte. Alcune piattaforms incorporate potrebbero essere diverse, ma sta diventando molto raro. Alcuni sistemi possono definire i tipi di char di 16 bit, nel qual caso probabilmente non ci sarà alcun tipo di 8 bit di alcun tipo.

A parte questo (minore) problema, la risposta di @Mark Ransom è la migliore secondo me. Usa quello che mostra più chiaramente per cosa stai usando i dati.

Inoltre, uint8_t che intendessi uint8_t (il typedef standard da C99 fornito nell’intestazione stdint.h ) piuttosto che uint_8 (non parte di nessuno standard).

L’intero punto è scrivere codice indipendente dall’implementazione. unsigned char non è garantito come un tipo a 8 bit. uint8_t è.

Come hai detto, ” quasi tutti i sistemi”.

char è probabilmente uno dei meno propensi a cambiare, ma una volta che inizi a usare uint16_t e gli amici, usando uint8_t mescola meglio e potresti persino far parte di uno standard di codifica.

Nella mia esperienza ci sono due punti in cui vogliamo usare uint8_t per indicare 8 bit (e uint16_t, ecc.) E dove possiamo avere campi più piccoli di 8 bit. Entrambi i luoghi sono dove lo spazio conta e spesso è necessario esaminare un dump raw dei dati durante il debug e devono essere in grado di determinare rapidamente ciò che rappresenta.

Il primo è nei protocolli RF, specialmente nei sistemi a banda stretta. In questo ambiente potremmo aver bisogno di raccogliere quante più informazioni ansible in un singolo messaggio. Il secondo è nella memoria flash, dove potremmo avere uno spazio molto limitato (come nei sistemi embedded). In entrambi i casi possiamo usare una struttura di dati imballata in cui il compilatore si occuperà del confezionamento e del disimballaggio per noi:

 #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() 

Il metodo che usi dipende dal tuo compilatore. Potrebbe inoltre essere necessario supportare diversi compilatori con gli stessi file di intestazione. Ciò accade nei sistemi integrati in cui dispositivi e server possono essere completamente diversi, ad esempio si può avere un dispositivo ARM che comunica con un server Linux x86.

Ci sono alcuni avvertimenti con l’uso di strutture confezionate. Il più grande trucchetto è che devi evitare di dereferenziare l’indirizzo di un membro. Sui sistemi con parole allineate mutibitate, ciò può provocare un’eccezione disallineata e un decodificatore.

Alcuni si preoccupano anche delle prestazioni e sostengono che l’utilizzo di queste strutture impacchettate rallenterà il tuo sistema. È vero che, dietro le quinte, il compilatore aggiunge il codice per accedere ai membri di dati non allineati. Potete vederlo guardando il codice assembly nel vostro IDE.

Ma dal momento che le strutture impacchettate sono più utili per la comunicazione e la memorizzazione dei dati, i dati possono essere estratti in una rappresentazione non compressa quando si lavora con esso in memoria. Normalmente non è necessario lavorare con l’intero pacchetto di dati in memoria.

Ecco alcune discussioni rilevanti:

pragma pack (1) né __attribute__ ((aligned (1))) funziona

Il pacchetto __attribute __ ((compresso)) / #pragma di gcc è pericoloso?

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

C’è poco Dal punto di vista della portabilità, char non può essere inferiore a 8 bit e nulla può essere più piccolo di char , quindi se una determinata implementazione C ha un numero intero a 8 bit senza segno, sarà char . In alternativa, potrebbe non averne affatto, a quel punto qualsiasi trucco typedef è discutibile.

Potrebbe essere usato per documentare meglio il tuo codice, nel senso che è chiaro che hai bisogno di byte da 8 bit lì e nient’altro. Ma in pratica è un’aspettativa ragionevole praticamente ovunque (ci sono piattaforms DSP su cui non è vero, ma le probabilità che il tuo codice funzioni lì sono ridotte, e potresti anche sbagliare usando un asser statico nella parte superiore del tuo programma su una tale piattaforma).

In quasi tutti i sistemi ho incontrato uint8_t == carattere senza segno, ma questo non è garantito dallo standard C. Se stai cercando di scrivere codice portatile e conta esattamente di quale dimensione è la memoria, usa uint8_t. Altrimenti usa il char non firmato.

Questo è molto importante ad esempio quando si scrive un analizzatore di rete. le intestazioni dei pacchetti sono definite dalla specifica del protocollo, non dal modo in cui un particolare compilatore C della piattaforma funziona.