Qual è il vantaggio di usare uint8_tover unsigned charin 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_tover unsigned charin 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_to int32_t.
unsigned charo signed chardocumentare anche l'intento, poiché disadorno charè ciò che mostra che stai lavorando con i personaggi.
unsignedfosse unsigned intper definizione?
charsembra 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 chartipi 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.hnell'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_tnon 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 charnon è garantito che sia un tipo a 8 bit. uint8_tè (se disponibile).
sizeof(unsigned char)tornerà 1per 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_te gli amici, usare le uint8_tmiscele 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à, charnon 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 typedeftrucchi 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 chardi essere in grado di contenere valori compresi tra 0 e 255. Se riesci a farlo in 4 bit, il mio cappello è spento.
uint8_tall'implementazione. Mi chiedo, i compilatori per DSP con caratteri a 16 bit in genere implementano uint8_to 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 chare al riempimento (nessuno) quando unsigned char è a 8 bit. Quando unsigned charnon è a 8 bit, uint8_tnon esiste.
unsigned charè 8-bit, viene uint8_tgarantita una typedefloro e non typedefdi un tipo intero senza segno esteso ?
unsigned char/signed char/charil tipo più piccolo, non inferiore a 8 bit. unsigned charnon ha imbottitura. Per uint8_tessere, 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.