Quel est l'avantage d'utiliser uint8_t
over unsigned char
en C?
Je sais que sur presque tous les systèmes, ce uint8_t
n'est qu'un typedef unsigned char
, alors pourquoi l'utiliser?
Quel est l'avantage d'utiliser uint8_t
over unsigned char
en C?
Je sais que sur presque tous les systèmes, ce uint8_t
n'est qu'un typedef unsigned char
, alors pourquoi l'utiliser?
Réponses:
Il documente votre intention - vous stockerez de petits nombres, plutôt qu'un caractère.
De plus, cela semble plus agréable si vous utilisez d'autres types de caractères tels que uint16_t
ou int32_t
.
unsigned char
ou signed char
documenter explicitement l'intention aussi, car sans fioritures char
est ce qui montre que vous travaillez avec des personnages.
unsigned
était unsigned int
par définition?
char
semble impliquer un caractère, alors que dans le contexte d'une chaîne UTF8, il peut ne s'agir que d'un octet d'un caractère multi-octets. L'utilisation de uint8_t pourrait indiquer clairement qu'il ne faut pas s'attendre à un caractère à chaque position - en d'autres termes que chaque élément de la chaîne / du tableau est un entier arbitraire sur lequel il ne faut pas faire d'hypothèses sémantiques. Bien sûr, tous les programmeurs C le savent, mais cela peut pousser les débutants à poser les bonnes questions.
Juste pour être pédant, certains systèmes peuvent ne pas avoir un type 8 bits. Selon Wikipedia :
Une implémentation est requise pour définir des types entiers de largeur exacte pour N = 8, 16, 32 ou 64 si et seulement si elle a un type qui répond aux exigences. Il n'est pas nécessaire de les définir pour tout autre N, même s'il prend en charge les types appropriés.
Il uint8_t
n'est donc pas garanti d'exister, bien qu'il le soit pour toutes les plates-formes où 8 bits = 1 octet. Certaines plates-formes intégrées peuvent être différentes, mais cela devient très rare. Certains systèmes peuvent définir des char
types sur 16 bits, auquel cas il n'y aura probablement aucun type sur 8 bits.
À part ce problème (mineur), la réponse de @Mark Ransom est la meilleure à mon avis. Utilisez celui qui montre le plus clairement pourquoi vous utilisez les données.
En outre, je suppose que vous vouliez dire uint8_t
(le typedef standard de C99 fourni dans l'en- stdint.h
tête) plutôt que uint_8
(ne faisant partie d'aucune norme).
uint8_t
(ou le taper typef pour cela). En effet, le type 8 bits aurait des bits inutilisés dans la représentation de stockage, qui uint8_t
ne doivent pas avoir.
typedef unsigned integer type uint8_t; // optional
Donc, en substance, une bibliothèque conforme à la norme C ++ n'est pas nécessaire du tout pour définir uint8_t (voir le commentaire // optionnel )
Le but est d'écrire du code indépendant de l'implémentation. unsigned char
n'est pas garanti comme étant de type 8 bits. uint8_t
est (si disponible).
sizeof(unsigned char)
retournera 1
pour 1 octet. mais si un système char et int ont la même taille, par exemple, 16 bits, alors sizeof(int)
ils reviendront également1
Comme vous l'avez dit, " presque tous les systèmes".
char
est probablement l'un des moins susceptibles de changer, mais une fois que vous commencez à utiliser uint16_t
et vos amis, vous utilisez uint8_t
mieux les mélanges, et peut même faire partie d'une norme de codage.
D'après mon expérience, il y a deux endroits où nous voulons utiliser uint8_t pour signifier 8 bits (et uint16_t, etc.) et où nous pouvons avoir des champs inférieurs à 8 bits. Les deux endroits sont où l'espace compte et nous avons souvent besoin de regarder un vidage brut des données lors du débogage et de pouvoir déterminer rapidement ce qu'il représente.
Le premier concerne les protocoles RF, en particulier dans les systèmes à bande étroite. Dans cet environnement, nous devrons peut-être regrouper autant d'informations que possible dans un seul message. Le second est dans le stockage flash où nous pouvons avoir un espace très limité (comme dans les systèmes embarqués). Dans les deux cas, nous pouvons utiliser une structure de données compressée dans laquelle le compilateur se chargera de l'emballage et du déballage pour nous:
#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()
La méthode que vous utilisez dépend de votre compilateur. Vous devrez peut-être également prendre en charge plusieurs compilateurs différents avec les mêmes fichiers d'en-tête. Cela se produit dans les systèmes embarqués où les périphériques et les serveurs peuvent être complètement différents - par exemple, vous pouvez avoir un périphérique ARM qui communique avec un serveur Linux x86.
Il y a quelques mises en garde concernant l'utilisation de structures compactes. Le plus gros problème est que vous devez éviter de déréférencer l'adresse d'un membre. Sur les systèmes avec des mots alignés sur plusieurs octets, cela peut entraîner une exception mal alignée - et un coredump.
Certaines personnes s'inquiéteront également des performances et soutiendront que l'utilisation de ces structures compressées ralentira votre système. Il est vrai que, dans les coulisses, le compilateur ajoute du code pour accéder aux membres de données non alignés. Vous pouvez le voir en regardant le code assembleur dans votre IDE.
Mais comme les structures compressées sont les plus utiles pour la communication et le stockage des données, les données peuvent être extraites dans une représentation non compressée lorsque vous travaillez avec elles en mémoire. Normalement, nous n'avons pas besoin de travailler avec le paquet de données entier en mémoire de toute façon.
Voici quelques discussions pertinentes:
pragma pack (1) ni __attribute__ ((aligné (1))) fonctionne
Le pack __attribute __ ((emballé)) / #pragma de gcc est-il dangereux?
http://solidsmoke.blogspot.ca/2010/07/woes-of-structure-packing-pragma-pack.html
Il y a peu. Du point de vue de la portabilité, char
ne peut pas être inférieur à 8 bits, et rien ne peut être inférieur à char
, donc si une implémentation C donnée a un type entier 8 bits non signé, ce sera le cas char
. Alternativement, il peut ne pas en avoir du tout, à quel point les typedef
astuces sont sans objet.
Il pourrait être utilisé pour mieux documenter votre code dans un sens qu'il est clair que vous avez besoin d'octets 8 bits et rien d'autre. Mais dans la pratique, c'est une attente raisonnable pratiquement n'importe où déjà (il existe des plates-formes DSP sur lesquelles ce n'est pas vrai, mais les chances que votre code s'exécute là-bas sont minces, et vous pourriez tout aussi bien vous tromper en utilisant une assertion statique en haut de votre programme sur une telle plateforme).
unsigned char
de pouvoir contenir des valeurs entre 0 et 255. Si vous pouvez le faire en 4 bits, mon chapeau est à vous.
uint8_t
à l'implémentation. Je me demande, les compilateurs pour DSP avec des caractères 16 bits implémentent-ils généralement uint8_t
ou non?
#include <stdint.h>
et d'utiliser uint8_t
. Si la plate-forme l'a, elle vous la donnera. Si la plate-forme ne l'a pas, votre programme ne sera pas compilé et la raison sera claire et simple.
C'est très important par exemple lorsque vous écrivez un analyseur de réseau. les en-têtes de paquet sont définis par la spécification du protocole, et non par le fonctionnement du compilateur C d'une plate-forme particulière.
Sur presque tous les systèmes, j'ai rencontré uint8_t == char non signé, mais ce n'est pas garanti par la norme C. Si vous essayez d'écrire du code portable et que la taille de la mémoire est exacte, utilisez uint8_t. Sinon, utilisez un caractère non signé.
uint8_t
correspond toujours à la plage et à la taille de unsigned char
et au remplissage (aucun) lorsqu'il unsigned char
est à 8 bits. Quand unsigned char
n'est pas 8 bits, uint8_t
n'existe pas.
unsigned char
est 8 bits, est uint8_t
garanti d'être un de typedef
ceux - ci et non un typedef
d'un type entier non signé étendu ?
unsigned char/signed char/char
le type le plus petit - pas plus petit que 8 bits. unsigned char
n'a pas de rembourrage. Pour uint8_t
être, il doit être de 8 bits, pas de remplissage, exister à cause d'une implémentation de type entier fourni: correspondant aux exigences minimales de unsigned char
. Quant à "... garanti d'être un typedef ..." ressemble à une bonne question à poster.