Qual è il vantaggio di usare uint8_t
over unsigned char
in C?
So che su quasi tutti i sistemi uint8_t
è solo un typedef per unsigned char
, quindi perché usarlo?
Qual è il vantaggio di usare uint8_t
over unsigned char
in C?
So che su quasi tutti i sistemi uint8_t
è solo un typedef per unsigned char
, quindi perché usarlo?
Risposte:
Documenta il tuo intento: memorizzerai piccoli numeri, piuttosto che un personaggio.
Inoltre sembra più bello se stai usando altri typedef come uint16_t
o int32_t
.
unsigned char
o signed char
documentare anche l'intento, poiché disadorno char
è ciò che mostra che stai lavorando con i personaggi.
unsigned
fosse unsigned int
per definizione?
char
sembra implicare un carattere, mentre nel contesto di una stringa UTF8, può essere solo un byte di un carattere multibyte. L'uso di uint8_t potrebbe chiarire che non ci si dovrebbe aspettare un carattere in ogni posizione, in altre parole che ogni elemento della stringa / matrice è un numero intero arbitrario sul quale non si dovrebbero fare ipotesi semantiche. Naturalmente tutti i programmatori C lo sanno, ma può spingere i principianti a porre le domande giuste.
Solo per essere pedanti, alcuni sistemi potrebbero non avere un tipo a 8 bit. Secondo Wikipedia :
È necessaria un'implementazione per definire tipi interi di larghezza esatta per N = 8, 16, 32 o 64 se e solo se ha un tipo che soddisfa i requisiti. Non è necessario definirli per nessun altro N, anche se supporta i tipi appropriati.
Così uint8_t
non è garantito che esista, sebbene lo sarà per tutte le piattaforme in cui 8 bit = 1 byte. Alcune piattaforme incorporate potrebbero essere diverse, ma sta diventando molto raro. Alcuni sistemi possono definire i char
tipi come 16 bit, nel qual caso probabilmente non ci sarà un tipo di 8 bit di alcun tipo.
Oltre a quello (minore) problema, la risposta di @Mark Ransom è la migliore secondo me. Usa quello che mostra più chiaramente a cosa stai utilizzando i dati.
Inoltre, suppongo che intendessi uint8_t
(il typedef standard di C99 fornito stdint.h
nell'intestazione) anziché uint_8
(non parte di alcuno standard).
uint8_t
(o darlo a quello). Questo perché il tipo a 8 bit avrebbe bit inutilizzati nella rappresentazione della memoria, che uint8_t
non devono avere.
typedef unsigned integer type uint8_t; // optional
Quindi, in sostanza, non è necessaria una libreria conforme allo standard C ++ per definire uint8_t (vedi il commento // opzionale )
Il punto è scrivere codice indipendente dall'implementazione. unsigned char
non è garantito che sia un tipo a 8 bit. uint8_t
è (se disponibile).
sizeof(unsigned char)
tornerà 1
per 1 byte. ma se un char di sistema e int hanno le stesse dimensioni di, per esempio, a 16 bit, allora sizeof(int)
tornerà anche1
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, usare le uint8_t
miscele meglio e potrebbe persino far parte di uno standard di codifica.
Nella mia esperienza ci sono due posti in cui vogliamo usare uint8_t per indicare 8 bit (e uint16_t, ecc.) E dove possiamo avere campi più piccoli di 8 bit. Entrambe le aree sono dove lo spazio è importante e spesso abbiamo bisogno di esaminare un dump grezzo dei dati durante il debug e dobbiamo essere in grado di determinare rapidamente ciò che rappresenta.
Il primo è nei protocolli RF, specialmente nei sistemi a banda stretta. In questo ambiente potrebbe essere necessario racchiudere quante più informazioni possibili in un singolo messaggio. Il secondo è nella memoria flash in cui potremmo avere uno spazio molto limitato (come nei sistemi embedded). In entrambi i casi possiamo utilizzare una struttura di dati impaccata in cui il compilatore si occuperà dell'imballaggio 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()
Quale metodo usi dipende dal tuo compilatore. Potrebbe anche essere necessario supportare diversi compilatori con gli stessi file di intestazione. Ciò accade nei sistemi embedded in cui dispositivi e server possono essere completamente diversi, ad esempio potresti avere un dispositivo ARM che comunica con un server Linux x86.
Ci sono alcune avvertenze sull'utilizzo di strutture impaccate. Il più grande gotcha è che devi evitare di dereferenziare l'indirizzo di un membro. Su sistemi con parole allineate mutibyte, ciò può comportare un'eccezione disallineata e un coredump.
Alcune persone si preoccuperanno anche delle prestazioni e sostengono che l'utilizzo di queste strutture impaccate rallenterà il sistema. È vero che, dietro le quinte, il compilatore aggiunge codice per accedere ai membri di dati non allineati. Puoi vederlo guardando il codice assembly nel tuo IDE.
Ma poiché le strutture impaccate sono più utili per la comunicazione e l'archiviazione dei dati, i dati possono essere estratti in una rappresentazione non impaccata quando si lavora con essa in memoria. Normalmente non abbiamo bisogno di lavorare con l'intero pacchetto di dati in memoria comunque.
Ecco alcune discussioni rilevanti:
pragma pack (1) né __attribute__ ((allineato (1))) funziona
Il pacchetto __attribute __ ((pacchetto)) / #pragma di gcc non è sicuro?
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 inferiore a char
, quindi se una determinata implementazione C ha un tipo intero a 8 bit senza segno, lo sarà char
. In alternativa, potrebbe non averne affatto uno, a quel punto tutti i typedef
trucchi sono discutibili.
Potrebbe essere usato per documentare meglio il tuo codice, nel senso che è chiaro che hai bisogno di byte a 8 bit lì e nient'altro. Ma in pratica è già una ragionevole aspettativa praticamente ovunque (ci sono piattaforme DSP su cui non è vero, ma le possibilità che il tuo codice sia in esecuzione sono scarse e potresti anche sbagliare usando un'asserzione statica nella parte superiore del tuo programma su tale piattaforma).
unsigned char
di essere in grado di contenere valori compresi tra 0 e 255. Se riesci a farlo in 4 bit, il mio cappello è spento.
uint8_t
all'implementazione. Mi chiedo, i compilatori per DSP con caratteri a 16 bit in genere implementano uint8_t
o no?
#include <stdint.h>
e usare uint8_t
. Se la piattaforma ce l'ha, te lo darà. Se la piattaforma non lo possiede, il programma non verrà compilato e il motivo sarà chiaro e chiaro.
Questo è molto importante, ad esempio, quando si scrive un analizzatore di rete. le intestazioni dei pacchetti sono definite dalle specifiche del protocollo, non dal modo in cui il compilatore C di una particolare piattaforma funziona.
Su quasi tutti i sistemi che ho incontrato uint8_t == char senza segno, ma questo non è garantito dallo standard C. Se stai cercando di scrivere un codice portatile e importa esattamente quale dimensione è la memoria, usa uint8_t. Altrimenti usa caratteri non firmati.
uint8_t
corrisponde sempre all'intervallo, alle dimensioni unsigned char
e al riempimento (nessuno) quando unsigned char
è a 8 bit. Quando unsigned char
non è a 8 bit, uint8_t
non esiste.
unsigned char
è 8-bit, viene uint8_t
garantita una typedef
loro e non typedef
di un tipo intero senza segno esteso ?
unsigned char/signed char/char
il tipo più piccolo, non inferiore a 8 bit. unsigned char
non ha imbottitura. Per uint8_t
essere, deve essere 8 bit, nessun padding, a causa di un'implementazione fornita di tipo intero: corrispondente ai requisiti minimi di unsigned char
. Quanto a "... garantito di essere un typedef ..." sembra una buona domanda da pubblicare.