web-dev-qa-db-fra.com

Quand uint8_t char est-il un caractère non signé?

Selon C et C++, CHAR_BIT >= 8.
Mais chaque fois que CHAR_BIT > 8, uint8_t ne peut même pas être représenté par 8 bits.
Il doit être plus grand, car CHAR_BIT est le nombre minimum de bits pour tout type de données sur le système.

Sur quel type de système peut uint8_t être légalement défini comme étant d'un type autre que unsigned char?

(Si la réponse est différente pour C et C++, j'aimerais connaître les deux.)

58
Mehrdad

S'il existe, uint8_t doit toujours avoir la même largeur que unsigned char. Cependant, il n'est pas nécessaire qu'il soit du même type; il peut s'agir d'un type entier étendu distinct. Il n'a pas non plus besoin d'avoir la même représentation que unsigned char; par exemple, les bits pourraient être interprétés dans l'ordre inverse. C'est un exemple stupide, mais il est plus logique pour int8_t, où signed char peut être un complément ou une amplitude de signe tandis que int8_t doit être un complément à deux.

Un autre "avantage" de l'utilisation d'un type entier étendu non char pour uint8_t même sur les systèmes "normaux", les règles d'aliasing de C. Les types de caractères sont autorisés à tout alias, ce qui empêche le compilateur d'optimiser fortement les fonctions qui utilisent à la fois des pointeurs de caractères et des pointeurs vers d'autres types, sauf si le mot clé restrict a été bien appliqué. Cependant, même si uint8_t a exactement la même taille et la même représentation que unsigned char, si l'implémentation en faisait un type distinct et sans caractère, les règles d'alias ne lui seraient pas applicables et le compilateur pourrait supposer que les objets de types uint8_t et int, par exemple, ne peuvent jamais être alias.

56
R..

Sur quel type de système peut uint8_t être légalement défini comme étant d'un type autre que unsigned char?

En résumé, uint8_t ne peut être défini légalement que sur les systèmes où CHAR_BIT est 8. C'est une unité adressable avec exactement 8 bits de valeur et aucun bit de remplissage.

En détail, CHAR_BIT définit la largeur des plus petites unités adressables et uint8_t ne peut pas avoir de bits de remplissage; il ne peut exister que lorsque la plus petite unité adressable a exactement 8 bits de largeur. Fournir CHAR_BIT est 8, uint8_t peut être défini par une définition de type pour tout type d'entier non signé 8 bits sans bit de remplissage.


Voici ce que dit le projet de norme C11 (n1570.pdf):

5.2.4.2.1 Tailles des types entiers 1 Les valeurs indiquées ci-dessous doivent être remplacées par des expressions constantes pouvant être utilisées dans les directives de prétraitement #if. ... Leurs valeurs définies par la mise en œuvre doivent être égales ou supérieures en valeur (valeur absolue) à celles indiquées, avec le même signe.

-- number of bits for smallest object that is not a bit-field (byte)
   CHAR_BIT                                            8

Ainsi, les plus petits objets doivent contenir exactement les bits CHAR_BIT.


6.5.3.4 Les opérateurs sizeof et _Alignof

...

4 Lorsque sizeof est appliqué à un opérande de type char, char non signé ou char signé, (ou une version qualifiée de celui-ci), le résultat est 1. ...

Ce sont donc (certaines) les plus petites unités adressables. Évidemment int8_t et uint8_t peut également être considérée comme la plus petite unité adressable, à condition qu'elle existe.

7.20.1.1 Types entiers de largeur exacte

1 Le nom typedef intN_t désigne un type entier signé de largeur N, sans bits de remplissage et une représentation du complément à deux. Ainsi, int8_t désigne un tel type entier signé avec une largeur d'exactement 8 bits.

2 Le nom de typedef uintN_t désigne un type entier non signé de largeur N et sans bits de remplissage. Ainsi, uint24_t désigne un tel type entier non signé avec une largeur d'exactement 24 bits.

3 Ces types sont facultatifs. Cependant, si une implémentation fournit des types entiers avec des largeurs de 8, 16, 32 ou 64 bits, pas de bits de remplissage et (pour les types signés) qui ont un complément à deux représentation, il définit les noms de typedef correspondants.

L'accent mis sur "ces types sont facultatifs" est le mien. J'espère que cela a été utile :)

30
autistic

Une possibilité que personne n'a mentionnée jusqu'à présent: si CHAR_BIT==8 Et non qualifié char n'est pas signé, ce qui est le cas dans certains ABI, alors uint8_t Pourrait être un typedef pour char au lieu de unsigned char. Cela importe au moins dans la mesure où il affecte le choix de surcharge (et son jumeau maléfique, le changement de nom), c'est-à-dire si vous devez avoir à la fois foo(char) et foo(unsigned char) dans la portée, en appelant foo avec un argument de type uint8_t préférerait foo(char) sur un tel système.

6
zwol