Si un tampon d'octets être signé ou non signé char buffer?
Devrait un tampon d'octets être signé char ou unsigned char ou tout simplement un char buffer?
Les différences entre le C et le C++?
Grâce.
- Dupe avec stackoverflow.com/questions/13819820
Vous devez vous connecter pour publier un commentaire.
Une petite différence dans la façon dont le langage de la traite. Un énorme différence dans la façon dont la convention de la traite.
char
= ASCII (ou UTF-8, mais la ce paramètre est dans la manière, y) textuelle donnéesunsigned char
= octetsigned char
= rarement utiliséEt il est le code que repose sur cette distinction. Tout juste une semaine ou deux il ya, j'ai rencontré un bug où les données de format JPEG a été corrompu parce qu'il était passé à la
char*
version de notre Base64 encode la fonction qui "utilement" remplacé tous les UTF-8 non valide dans la "chaîne". Changer deBYTE
akaunsigned char
, il n'en fallait pour le fixer.char*
au lieu deunsigned char*
pour représenter les tampons de données lors de la lecture et de l'écriture binaire des flux à traversread
etwrite
méthodes? 😛char
), plutôt que de dire, comme certains autres langages comme Pascal l'avait fait--que la seule unsigned types devraient être celles qui ferait la promotion d'un entier signé de type.Si vous avez l'intention de stocker des données binaires arbitraires, vous devez utiliser
unsigned char
. C'est le seul type de données est garanti ont pas de rembourrage bits par la Norme. Chaque autre type de données peut contenir rembourrage bits dans sa représentation d'objet (qui est celui qui contient tous les bits d'un objet, non seulement à ceux qui détermine une valeur). Le remplissage des bits d'état est indéterminée et ne sont pas utilisés pour stocker des valeurs. Donc, si vous lisez l'aide dechar
des données binaires, les choses allaient être coupés à la plage de valeurs de type char (par l'interprétation que la valeur des bits), mais il existe peut-être les bits qui sont tout simplement ignorés, mais sont toujours là et lu parmemcpy
. Un peu comme le rembourrage de bits dans la vraie structure des objets. Typeunsigned char
est garanti de ne pas contenir de ceux-ci. Qui suit à partir de5.2.4.2.1/2
(C99 TC2, n1124 ici):De la dernière phrase, il s'ensuit qu'il n'y a pas d'espace à gauche pour tout remplissage bits. Si vous utilisez
char
que le type de votre tampon, vous avez aussi le problème de débordement: Attribuant une valeur explicitement à un tel élément, qui est dans la gamme de8
bits, de sorte que l'on peut attendre d'une telle attribution d'être OK, mais pas dans la gamme d'unchar
, qui estCHAR_MIN
..CHAR_MAX
, une telle conversion des débordements et des causes de la mise en œuvre des résultats, y compris l'augmentation de signaux.Même si des problèmes concernant le ci-dessus serait probablement pas dans les mises en production (serait un très la mauvaise qualité de la mise en œuvre), vous êtes mieux d'utiliser le bon type depuis le début, qui est
unsigned char
.Pour les cordes, cependant, le type de données de choix est
char
, qui sera comprise par la chaîne de caractères et de fonctions d'impression. À l'aide designed char
à ces fins ressemble à une mauvaise décision pour moi.Pour plus d'informations, lisez
cette proposition
qui contient un correctif pour une prochaine version de la Norme C qui finira par exigersigned char
pas tout padding bits soit. C'est déjà incorporé dans le document de travail.[C++11: 3.9.1/1]:
[..] Un char, un signed char et unsigned char occupent le même espace de stockage et d'avoir les mêmes exigences alignement (3.11), c'est qu'ils ont le même objet de la représentation. Pour les types de caractères, tous les bits de la représentation d'objet de participer à la représentation de la valeur. [..] N'est-ce pas suggérer que tous les trois types de caractères ont, à tout le moins, le même rembourrage? Et je l'interpréter plus loin pour dire qu'aucun d'entre eux en ont.uintN_t
etintN_t
ne pas non plus avoir des octets de remplissage.Il dépend.
Si la mémoire tampon est destiné à contenir du texte, alors il est probablement de sens que de le déclarer comme un tableau de
char
et de laisser la plate-forme de décider pour vous si c'est signé ou non signé par défaut. Qui vous donnera le moins de difficulté à passer les données dans et hors de la mise en œuvre de l'exécution de la bibliothèque, par exemple.Si la mémoire tampon est destiné à contenir des données binaires, ensuite, cela dépend de comment vous avez l'intention de l'utiliser. Par exemple, si les données binaires est vraiment un panier éventail d'échantillons de données qui sont signés sur 8 bits à virgule fixe ADC mesures, puis
signed char
serait le mieux.Dans la plupart du monde réel des cas, le tampon est un tampon, et vous n'avez pas vraiment sur les types de l'individu octets parce que vous avez rempli le tampon dans une opération en bloc, et vous êtes sur le point de passer à un analyseur d'interpréter la structure de données complexe et de faire quelque chose d'utile. Dans ce cas, le déclarer de la manière la plus simple.
Si il est en fait une mémoire tampon de 8 bits, octets, plutôt qu'une chaîne de caractères dans la machine locale par défaut, puis je utiliser
uint8_t
. Pas qu'il y a de nombreuses machines où un char n'est pas un octet (ou un octet un octet), mais qui fait la déclaration "c'est un tampon d'octets' plutôt que 'ceci est une chaîne' est souvent utile de documentation.Vous devez utiliser char ou unsigned char mais jamais signed char. Le standard a de la suite dans 3.9/2
Il est préférable de la définir comme unsigned char. Enfait Win32 OCTET de type est défini comme un unsigned char. Il n'y a pas de différence entre le C & C++ entre ce.
Pour un maximum de portabilité toujours utiliser unsigned char. Il y a quelques cas où cela pourrait venir en jeu. Données sérialisées partagés entre les systèmes avec différents endian type vient immédiatement à l'esprit. Lors de l'exécution de maj ou le bit de masquage des valeurs est une autre.
Le choix de int8_t vs u_int8_t est similaire à lorsque vous comparez un pointeur à NULL.
À partir d'une fonctionnalité de point de vue, la comparaison à la valeur NULL est la même que la comparaison de 0 pour la valeur NULL est un #define pour 0.
Mais, personnellement, à partir d'un style de codage point de vue, j'ai choisi de comparer mes pointeurs à NULL car le NULL #define évoque à la personne de maintenir le code que vous êtes à la recherche d'une mauvaise pointeur...
VS
quand quelqu'un voit une comparaison à 0, cela signifie que vous êtes à la recherche d'une valeur spécifique.
Pour la raison invoquée ci-dessus, je voudrais utiliser u_int8_t.
Si vous chercher un élément d'une plus grande variable, elle sera évidemment signe étendu ou non.
Devrait ... j'ai tendance à préférez unsigned, car il se sent plus "brut", de moins en moins accueillante pour dire "hey, c'est juste un tas de petites
ints
", si je tiens à souligner le binaire-ness de données.Je ne pense pas que je ai jamais utilisé explicite
signed char
pour représenter un tampon d'octets.Bien sûr, une troisième option est de représenter le tampon de
void *
autant que possible. De nombreuses fonctions d'e/S de travail avecvoid *
, de sorte que parfois, la décision de ce type entier à utiliser peut être entièrement encapsulé, ce qui est agréable.Il y a plusieurs années j'ai eu un problème avec une application console C++ qui a imprimé coloré caractères ASCII pour les valeurs au-dessus de 128 et cela a été résolu par le passage de char, unsigned char, mais je crois que ça avait été solveable tout en gardant type char, trop.
Pour l'instant, la plupart des C/C++ des fonctions utilisation de char et je comprends les deux langues beaucoup mieux maintenant, donc j'utilise char dans la plupart des cas.
Faire vous vous souciez vraiment? Si vous n'en avez pas, il suffit d'utiliser la valeur par défaut (char) et de ne pas encombrer votre code avec l'importance de la matière. Sinon, futurs responsables sera de vous demander pourquoi vous utilisez signé ou non signé). Leur rendre la vie plus simple.
Si vous mentez pour le compilateur, il va vous punir.
Si la mémoire contient des données qui sont juste de passage, et vous ne pourrez pas manipuler d'une quelconque façon, il n'a pas d'importance.
Toutefois, si vous avez à fonctionner sur le contenu de la mémoire tampon, puis le type correct de la déclaration de rendre votre code plus simple. Pas de "int val = buf[i] & 0xff;" non-sens.
Alors, pensez à ce que les données est réellement et comment vous devez l'utiliser.
Maintenant vous pouvez faire votre tableau de
byte
s. Il est évident pour tout le monde ce que vous vouliez, et vous ne perdez pas toutes les fonctionnalités.Je sais que c'est un peu bête, mais cela rend votre code de lecture de 100% comme vous le souhaitez.
typedef unsigned char BYTE
.