Définissez tous les octets de int sur (caractère non signé) 0, garanti pour représenter zéro?

Ce n’est pas une question de pratique recommandée (ni de comportement non défini ), mais de ce que la norme c ++ garantit réellement en ce qui concerne la conversion de tous les octets d’un type entier à la valeur de (unsigned char)0 .


Questions)

Dans l’extrait de code ci-dessous, l’expression utilisée par l’ instruction if est-elle garantie évaluée à true dans c ++ 11 ?

 std::memset ( reinterpret_cast (&a), // int a; (unsigned char)0, sizeof (int) ); if (a == 0) { ... } 

En lisant les citations du standard C99 et C ++ 11 (plus bas dans cet article), nous constatons que C99 garantit explicitement qu’un type entier avec tous les bits mis à 0 représentera la valeur 0 dans ce type.

Je ne trouve pas cette garantie dans la norme C ++ 11.

  • N’y a-t-il pas une telle garantie?
  • Le résultat de l’extrait de code précédent est-il vraiment spécifique à l’implémentation?


En C99 (ISO / IEC 9899: 1999)

5.2.1.2/1 Caractères multi-octets

Un octet avec tous les bits nuls doit être interprété comme un caractère nul indépendamment de l’état de décalage. Un tel octet ne doit pas faire partie d’un autre caractère multi-octets.

6.2.6.2/1 Types entiers

Les valeurs des bits de remplissage ne sont pas spécifiées. 45) Une représentation d’object valide (sans interruption) d’un type entier signé dont le bit de signe est zéro est une représentation d’object valide du type non signé correspondant et doit représenter la même valeur.

Pour tout type entier, la représentation d’object où tous les bits sont nuls doit représenter la valeur zéro dans ce type.



En C ++ 11 (ISO / IEC 14882: 2011)

2.3 / 3 Jeux de caractères [lex.charset]

Le jeu de caractères d’exécution de base et le jeu de caractères larges d’exécution de base doivent contenir tous les membres du jeu de caractères source de base, ainsi que des caractères de contrôle représentant l’alerte, le retour arrière et le retour chariot, respectivement un caractère nul dont la représentation a tous les bits zéro .

C ++ 11

Je pense que la partie pertinente est

3.9.1 / 1 En C ++ 11

Pour les types de caractères, tous les bits de la représentation d’object participent à la représentation des valeurs. Pour les types de caractères non signés, tous les modèles de bits possibles de la représentation de la valeur représentent des nombres. Ces exigences ne sont pas valables pour d’autres types.

Avec 3.9.1 / 7

Les représentations de types intégraux doivent définir des valeurs en utilisant un système de numération binary pur.

C11

6.2.6.2 est très explicite

Pour les types d’entiers non signés autres que les caractères non signés, les bits de la représentation d’object doivent être divisés en deux groupes: les bits de valeur et les bits de remplissage (il n’y a pas besoin de ces derniers). S’il y a N bits de valeur, chaque bit doit représenter une puissance différente de 2 entre 1 et 2 N-1 , afin que les objects de ce type puissent représenter des valeurs de 0 à 2 N-1 en utilisant une représentation binary pure; cela doit être connu comme la représentation de la valeur. Les valeurs des bits de remplissage ne sont pas spécifiées.

Pour les types entiers signés, les bits de la représentation d’object doivent être divisés en trois groupes: les bits de valeur, les bits de remplissage et le bit de signe. Il n’y a pas besoin de bits de remplissage; le caractère signé ne doit pas comporter de bits de remplissage. Il y aura exactement un bit de signe. Chaque bit qui est un bit de valeur doit avoir la même valeur que le même bit dans la représentation d’object du type non signé correspondant (s’il y a M bits de valeur dans le type signé et N dans le type non signé, alors M ≤ N). Si le bit de signe est zéro, cela n’affecte pas la valeur résultante. Si le bit de signe est un, la valeur doit être modifiée de l’une des manières suivantes:

– la valeur correspondante avec le bit de signe 0 est annulée (signe et magnitude);

– le bit de signe a la valeur – (2 M ) (complément à deux);

– le bit de signe a la valeur – (2 M – 1 ) (complément d’un).

Laquelle de ces applications est définie par l’implémentation, de même que la valeur avec le bit de signe 1 et tous les bits de valeur zéro (pour les deux premiers) ou avec le bit de signe et tous les bits de valeur 1 (pour le complément) ou une valeur normale. Dans le cas du signe et de la magnitude et du complément, si cette représentation est une valeur normale, elle est appelée un zéro négatif.

Summmary

Je pense que l’intention est la même pour les deux standards.

  • char , le caractère signed char et le caractère unsigned char ont tous les bits participant à la valeur

  • d’autres types entiers peuvent avoir des bits de remplissage qui ne participent pas à la valeur. Un modèle de bit incorrect peut impliquer une valeur non valide.

  • l’interprétation est une représentation binary pure, quelque chose dont la définition est développée dans la citation C11 ci-dessus.

Deux choses qui peuvent ne pas être claires:

  • can -0 (pour le signe et la magnitude et le complément de _ones) soit une valeur de piège en C ++

  • l’un des bits de remplissage peut-il être un bit de parité (peut-on modifier la représentation si l’on s’assure que les bits de remplissage ne sont pas modifiés ou non)

Je serais conservateur et supposerais oui pour les deux.

Nan. Par exemple, rien dans la norme n’interdit une représentation fondée sur les préjugés, elle exige seulement que ce soit binary.

Oui, c’est garanti.

La rotation de tous les octets / bits d’un type entier est garantie pour qu’une instance du type ait la valeur zéro ( 0 ), comme indiqué par les extraits ci-dessous de la norme mentionnée.


3.9.1 / 7 Types fondamentaux

Un synonyme de type intégral est un type entier. Les représentations de types intégraux doivent définir des valeurs en utilisant un système de numération binary pur. 49

49 représentation positionnelle pour les entiers qui utilisent les chiffres binarys 0 et 1, dans lesquels les valeurs représentées par les bits successifs sont additifs, commencent par 1 et sont multipliées par la puissance intégrale successive de 2, sauf peut-être pour le bit ayant la position la plus élevée. (Adapté du Dictionnaire national américain pour les systèmes de traitement de l’information .)

Non, je ne crois pas que ce soit garanti, mais c’est plutôt vague.

Je serais très surpris qu’il y ait jamais eu une implémentation C ++ dans laquelle tous les bits nuls n’est pas une représentation de 0 , mais je pense qu’une telle implémentation pourrait être conforme (bien que perverse).

Commençons par considérer le standard C99. (Oui, je sais, la question porte sur C ++; supportez-moi.) Il dit que les bits de la représentation d’object d’un type entier non signé sont divisés en deux groupes: bits de valeur et bits de remplissage (il n’y a pas besoin de remplissage) bits, et la plupart des implémentations ne les ont pas). Les bits de valeur constituent une représentation binary pure; les bits de remplissage ne consortingbuent pas à la valeur. Certaines combinaisons de bits de remplissage peuvent générer une représentation d’interruption .

Les types signés sont similaires, avec l’ajout d’un seul bit de signe. Les types signés peuvent être représentés en utilisant soit le signe et la magnitude , soit le complément à deux , soit le complément – mais encore une fois, les bits de remplissage ne consortingbuent pas à la valeur et certaines combinaisons de bits de remplissage peuvent générer des représentations de pièges.

Cette description n’exclut pas la possibilité que, par exemple, un type entier plus large que char puisse avoir un seul bit de remplissage qui doit toujours être 1; si c’est 0, vous avez une représentation de piège. Ou, peut-être plus vraisemblablement, il pourrait avoir un bit de parité étrange.

Après la publication de la norme C99, le deuxième corrigendum technique a ajouté la phrase suivante, qui figure également en C11.

Pour tout type entier, la représentation d’object où tous les bits sont nuls doit représenter la valeur zéro dans ce type.

J’insiste sur le fait que cela a été ajouté en tant que texte normatif, et non en tant que note de bas de page, ce qui suggère (mais ne prouve pas) que les membres du comité estimaient que la garantie n’était pas déjà implicite dans la norme C99.

(C90 était beaucoup moins précis quant à la représentation des types entiers. Il ne mentionnait pas les bits de remplissage, les représentations de pièges ou le complément à deux et je dirais que cela a donné au moins autant de flexibilité que C99.)

Donc, à partir de C99 TC2, le langage C garantit que tout-zéro-bit est une représentation de zéro pour tout type entier. En C99 et C90, cette garantie n’est pas indiquée.

C’est C. Qu’en est-il du C ++?

La norme C ++ 2011 semble ne fournir qu’une spécificité légèrement plus grande sur les représentations de type entier comme l’ancienne norme C de 1990. Les types signés doivent être représentés en utilisant soit le complément à 2, soit le complément à 1, soit la magnitude signée. Il nécessite également un “système de numération binary pur”. Il ne mentionne pas les «représentations de pièges», ni les bits de remplissage, sauf dans le contexte des champs de bits.

Ainsi, dans les deux versions C90 et pré-TC2 C99, il était théoriquement possible que le tout-zéro soit une représentation d’interruption pour un type entier. Les exigences du standard C ++ pour les types entiers sont très similaires à celles de C90 et C99. Cela nécessite une “représentation binary pure”, mais je dirais que cela ne s’applique, comme dans C99, qu’aux bits de valeur; bien que C ++ ne mentionne pas les bits de remplissage, cela ne les interdit pas.

Là encore, il s’agit principalement d’un intérêt théorique (donc l’étiquette «langue-avocat»). Le comité C s’est senti libre d’imposer l’exigence que tous les bits-zéro doivent être une représentation de zéro car toutes les implémentations l’ont déjà satisfait. La même chose s’applique presque certainement au C ++.