43 votes

Définir tous les octets de l'entier à (unsigned char)0, garanti de représenter zéro?

Ce n'est pas une question de <em>pratique recommandée</em> (ni de <em>comportement indéfini</em>), mais de ce que garantit réellement la norme <em>c++</em> en matière de conversion de tous les octets d'un type entier à la valeur de <code>(unsigned char)0</code>.


La ou les question(s)

Dans l'extrait ci-dessous, l'expression utilisée par la condition if est-elle garantie d'être évaluée à true en c++11 ?

std::memset (
  reinterpret_cast (&a), // int a;
  (unsigned char)0,
  sizeof (int)
);

if (a == 0) {
  ...
}

En consultant les citations de la norme C99 et C++11 (plus loin dans ce post), nous constatons que la norme C99 garantit explicitement qu'un type entier avec tous les bits définis à 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 précédent est-il vraiment spécifique à l'implémentation ?


Dans C99 (ISO/IEC 9899:1999)

5.2.1.2/1 Caractères multioctets

Un octet avec tous les bits à zéro doit être interprété comme un caractère nul indépendamment de l'état de décalage. Un tel octet ne doit pas apparaître comme partie d'un autre caractère multioctet.

6.2.6.2/1 Types entiers

Les valeurs de tous les bits de remplissage sont non spécifiées. 45) Une représentation d'objet valide (non piégée) d'un type entier signé où le bit de signe est zéro est une représentation d'objet valide du type non signé correspondant, et doit représenter la même valeur.

Pour tout type entier, la représentation d'objet où tous les bits sont à zéro doit être une représentation de la valeur zéro dans ce type.



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

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

L'ensemble de caractères d'exécution de base et l'ensemble de caractères larges d'exécution de base doivent contenir chacun tous les membres de l'ensemble de caractères source de base, ainsi que des caractères de contrôle représentant une alerte, un retour arrière et un retour chariot, plus un caractère nul (respectivement, caractère nul large), dont la représentation a tous les bits à zéro.

14voto

AProgrammer Points 31212

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 de l'objet participent à la représentation de la valeur. Pour les types de caractères non signés, toutes les combinaisons de bits possibles de la représentation de la valeur représentent des nombres. Ces exigences ne s'appliquent pas à d'autres types.

Ainsi que 3.9.1/7

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

C11

6.2.6.2 est très explicite

Pour les types entiers non signés autres que unsigned char, les bits de la représentation de l'objet doivent être divisés en deux groupes : bits de valeur et bits de bourrage (il n'y en a pas forcément). S'il y a N bits de valeur, chaque bit doit représenter une puissance différente de 2 entre 1 et 2N−1, de sorte que les objets de ce type soient capables de représenter des valeurs de 0 à 2N − 1 en utilisant une représentation binaire pure ; cela sera appelé la représentation de la valeur. Les valeurs de tout bit de bourrage sont non spécifiées.

Pour les types entiers signés, les bits de la représentation de l'objet doivent être divisés en trois groupes : bits de valeur, bits de bourrage et le bit de signe. Il n'y a pas forcément de bits de bourrage ; signed char ne doit pas avoir de bits de bourrage. Il doit y avoir 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 de l'objet du type non signé correspondant (si le type signé a M bits de valeur et le type non signé a N, alors M ≤ N). Si le bit de signe est zéro, il ne doit pas affecter 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 niée (signe et magnitude) ;

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

— le bit de signe a la valeur −(2M − 1) (complément à un).

Lequel de ces cas s'applique est défini par l'implémentation, de même que si la valeur avec un bit de signe 1 et tous les bits de valeur à zéro (pour les deux premiers), ou avec un bit de signe et tous les bits de valeur à 1 (pour le complément à un), est une représentation de piège ou une valeur normale. Dans le cas du signe et de la magnitude et du complément à un, si cette représentation est une valeur normale, on parle de zéro négatif.

Résumé

Je pense que l'intention est la même pour les deux normes.

  • char, signed char et unsigned char ont tous les bits participant à la valeur

  • les autres types entiers peuvent avoir des bits de bourrage qui ne participent pas à la valeur. Un motif de bits incorrect dans ceux-ci peut impliquer une valeur non valide.

  • l'interprétation est une représentation binaire pure, dont la définition est étendue dans la citation C11 ci-dessus.

Deux choses qui peuvent ne pas être claires :

  • est-ce que -0 (pour le signe et magnitude et le complément à un) peut être une valeur de piège en C++

  • est-ce qu'un des bits de bourrage peut être un bit de parité (c'est-à-dire est-ce que nous pouvons modifier la représentation si nous nous assurons que les bits de bourrage ne sont pas modifiés ou non)

Je serais conservateur et assumerais que oui pour les deux.

2voto

Filip Roséen - refp Points 24995

Oui, c'est garanti.

Le fait de retourner tous les octets / bits d'un type entier est garanti de faire en sorte qu'une instance du type ait la valeur zéro (0), comme le précise l'extrait suivant(s) de la norme mentionnée.


3.9.1/7 Types fondamentaux

Un synonyme de type intégral est le type entier. _Les représentations des types entiers doivent définir les valeurs par l'utilisation d'un système de numération binaire pur._49

49représentation de position pour les entiers qui utilise les chiffres binaires 0 et 1, dans laquelle les valeurs représentées par les bits successifs sont additives, commencent par 1, et sont multipliées par des puissances entières successives de 2, sauf peut-être pour le bit de position le plus élevée. (Adapté du <em>Dictionnaire National Américain pour les Systèmes de Traitement de l'Information</em>.)

2voto

Puppy Points 90818

Non. par exemple, il n'y a rien dans la norme interdisant une représentation basée sur les préjugés, elle exige seulement qu'elle soit binaire.

0voto

Keith Thompson Points 85120

Non. Je ne crois pas que ce soit effectivement garanti, mais c'est plutôt vague.

Je serais très surpris s'il y ait jamais eu une implémentation C++ dans laquelle tous les bits à zéro ne représentent pas un 0, mais je crois qu'une telle implémentation pourrait être conforme (bien que perverse).

Commençons par considérer la norme C99. (Oui, je sais, la question concerne le C++; patientez avec moi.) Elle dit que les bits de la représentation objet d'un type entier non signé sont divisés en deux groupes: bits de valeur et bits de remplissage (il n'est pas nécessaire qu'il y ait des bits de remplissage, et la plupart des implémentations n'en ont pas). Les bits de valeur forment une représentation binaire pure; les bits de remplissage ne contribuent pas à la valeur. Certaines combinaisons de bits de remplissage pourraient générer une représentation de piège.

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 un signe et magnitude, soit le complément à deux, soit le complément à un -- mais encore une fois, aucun bit de remplissage ne contribue à la valeur, et certaines combinaisons de bits de remplissage peuvent générer des représentations de piège.

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; s'il est à 0, vous avez une représentation de piège. Ou, peut-être plus plausible, il pourrait avoir un bit de parité impair.

Après la publication de la norme C99, le deuxième Corrigendum technique a ajouté la phrase suivante, qui apparaît également dans C11.

Pour tout type entier, la représentation objet où tous les bits sont à zéro doit être une représentation de la valeur zéro dans ce type.

Je souligne que ceci 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 spécifique sur la façon dont les types entiers sont représentés. Il ne mentionnait pas les bits de remplissage, les représentations de piège ou le complément à deux, entre autres. Je soutiendrais qu'il donnait aux implémentations au moins autant de flexibilité que C99.)

Donc, à partir de C99 TC2, le langage C garantit que tous les bits à zéro sont une représentation de zéro pour tout type entier. Dans C99 et C90, cette garantie n'est pas spécifiée.

C'est pour C. Et pour le C++ ?

La norme C++ de 2011 semble fournir juste un peu plus de spécificité sur les représentations de types entiers que l'ancienne norme C de 1990. Elle exige que les types signés soient représentés en utilisant le complément à deux, le complément à un ou la magnitude signée. Elle exige également un "système de numération binaire pure". Elle ne mentionne pas les "représentations de piège", et ne discute pas des bits de remplissage sauf dans le contexte des champs de bits.

Alors, dans C90 et en pré-TC2 de C99, il était au moins théoriquement possible que tous les bits à zéro soient une représentation de piège pour un type entier. Les exigences de la norme C++ pour les types entiers sont très similaires à celles de C90 et C99. Elle exige une "représentation binaire pure", mais je soutiendrais que cela s'applique, comme dans C99, uniquement aux bits de valeur; bien que le C++ ne mentionne pas les bits de remplissage, il ne les interdit pas.

Encore une fois, ceci est principalement d'intérêt théorique (d'où la balise "avocat du langage"). 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 parce que toutes les implémentations le satisfaisaient déjà. Il en va probablement de même pour le C++.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X