10
votes

Comportement de coulée booléen étrange c ++ (vrai! = Vrai)

Il suffit de lire sur un thread de l'université interne: xxx

donc a , b et wb sont Tous déclaré comme bool . A est attribué 1 , b est attribué 2 et la représentation interne de wb est modifié en 2 (en utilisant un union ).

de cette façon, tous a , B < / code> et wb sera true , mais a et wb ne sera pas égal, donc cela pourrait donc signifie que l'univers est cassé ( vrai! = true )

Je sais que ce problème est plus théorique que pratique (un programmeur à saké ne veut pas modifier la représentation interne d'un bool ), mais voici les questions suivantes:

  1. Est-ce que ça va? (Ceci a été testé avec g ++ 4.3.3) Je veux dire, si le compilateur doit être conscient que pendant la comparaison booléenne toute valeur non nulle peut signifier VRAI?
  2. Connaissez-vous des cas où cette affaire de coin pourrait devenir un véritable problème? (Par exemple, lors du chargement de données binaires à partir d'un flux)

    EDIT:

    Trois choses:

    1. bool et int ont des tailles différentes, c'est bon. Mais si j'utilise si j'utilise char au lieu de int . Ou lorsque tailleOf (bool) == taille de (int) ?

    2. S'il vous plaît donner une réponse aux deux questions que j'ai posées si possible. Je suis également intéressé par les réponses aux deuxièmes questions, car dans mon opinion honnête, dans des systèmes intégrés (qui pourraient être des systèmes de 8 bits), cela pourrait être un vrai problème (ou non).

    3. nouvelle question: est-ce vraiment comportement non défini? Si oui, pourquoi? Sinon, pourquoi? Il n'y a aucune hypothèse sur les opérateurs de comparaison booléenne dans les spécifications?


1 commentaires

GCC sonne juste le bit le moins significatif lors du fait de ! B et B est de type bool . Donc, un 1 devient 0 et inversement, sans ramification. En outre, lors du fait de int A = B; rien n'est nécessaire pour être comparé (alors seul un geste est nécessaire). Il est donc logique de stocker un bool en tant que numéro 0 et 1 (mais cela n'est pas spécifié par la norme). Dans votre code, wb est pas true (car GCC utilise 1 pour représenter true, pas 2 ). w.b a non valeur. Il a une représentation piège. Lire c'est comportement indéfini .


8 Réponses :


0
votes

hmm étrange, je reçois une sortie différente de CodePad:

11
111
122222
T

Le code me semble aussi juste pour moi, peut-être que c'est un bug de compilateur?
voir ici


2 commentaires

Le code a un comportement indéfini, de sorte que Bery fonctionnera probablement différemment (s'il fonctionne du tout) sur différentes plates-formes. Ce n'est pas un "bogue de compilateur" - avant de toujours utiliser ces mots, réfléchissez deux fois, puis réfléchissez à nouveau à nouveau à nouveau.


Merci :) Cela me semblait tellement étrange pour moi. Je n'ai pas vu l'Union. Je pensais que c'était une structure simple.



9
votes

Normalement, lorsque vous attribuez une valeur arbitraire à un bool code> le compilateur le convertira pour vous:

bool z = (x != 0) ? true : false;


2 commentaires

Oui, mais est-ce un bogue du compilateur, ou est-ce simplement indéfini dans les spécifications. Un compilateur peut toujours créer un ((((A! = 0) && (B! = 0)) || ((A == 0) && (B == 0))) au lieu de simplement vérifier les bits.


Il s'agit d'un comportement indéfini d'accéder à un membre d'une union autre que le dernier dans lequel une valeur a été stockée.



17
votes

Si vous lisez un membre d'un syndicat qui est un membre différent que le dernier membre qui a été écrit, vous obtenez un comportement indéfini. Écrire un membre INT puis lire le membre Bool de l'Union pourrait entraîner quelque chose à tout point ultérieur du programme.

La seule exception est l'endroit où les syndicats sont une union des structures et toutes les structures contiennent une séquence initiale commune, auquel cas la séquence commune peut être lue.


4 commentaires

Oui, mais si j'ai une structure avec un bool dedans, et je lis des données dans cette structure d'un fichier. De cette façon, je n'utilise pas les syndicats, mais obtenez toujours les "mauvaises" données dans la variable Bool.


Ensuite, c'est une autre question, ou éditez votre actuel et modifiez le code.


Encore une fois, comportement indéfini. Vous ne pouvez pas lire des modèles de bits arbitraires dans des variables C ++ et attendez-les à leur "travailler".


Afaict, la seule garantit que les états standard sont que toute valeur zéro arithmétique convertie en un bool avec être false et tous les autres seront true . De même, une valeur BOOL sera convertie en une valeur zéro dans tout type arithmétique pour false et un pour true . Au-delà de cela, fwrite ((vide *) & b, taille de (B), 1, fp) écrira le nombre d'octets associés à B de telle manière que Fread ((vide *) & B, taille de (B), 1, FP) entraînera la même valeur. Rien n'est dit sur le nombre d'octets écrits ou sa valeur binaire. En outre, considérons que tailleof (bool) et tailleof (int) peut différer ...



1
votes

Je crois ce que tu fais est appelé type punning: http://fr.wikipedia.org/wiki/type_punning


0 commentaires

2
votes

Le booléen est un octeen et l'entier est quatre octets. Lorsque vous attribuez 2 à l'entier, le quatrième octet a une valeur de 2, mais le premier octet a une valeur de 0. Si vous lisez le booléen à l'extérieur de l'Union, cela va prendre le premier octet.

EDIT: D'Oh. Comme l'indique Oleg Zhylin, cela ne s'applique qu'à un processeur Big-Endian. Merci pour la correction.


1 commentaires

Je suppose que la plupart des gens sont sur des machines de petite endansion. Mais +1 pour le pointant de cela.



0
votes

juste pour écrire mes points de vue:

  1. est-ce que ça va?

    Je ne sais pas si les spécifications spécifient quoi que ce soit à ce sujet. Un compilateur peut toujours créer un code comme celui-ci: ((A! = 0) && (B! = 0)) || ((A == 0) && (B == 0)) Lorsque cela comparait deux booléens, bien que cela puisse diminuer les performances.

    À mon avis, ce n'est pas un bogue, mais un comportement non défini. Bien que je pense que chaque implémentatif devrait indiquer aux utilisateurs comment les comparaisons booléennes sont effectuées dans leur mise en œuvre.

  2. n'importe quel cas réel

    La seule chose qui apparaît dans mon esprit, si quelqu'un lit des données binaires d'un fichier dans une structure, qui ont des membres BOOL. Le problème pourrait augmenter si le dossier a été effectué avec un autre programme qui a écrit 2 au lieu de 1 à la place du Bool (peut-être parce qu'il a été écrit dans un autre langage de programmation).

    Mais cela pourrait signifier une mauvaise pratique de programmation.

    Un de plus: Dans les systèmes embarqués Ce bug pourrait être un problème plus important que sur un système "normal", car les programmeurs font généralement plus de "magique bit" pour faire le travail.


3 commentaires

"Avis" ne vient pas dedans. C'est un bug ou un comportement non défini (ou quelque chose d'autre). Et le point entier du comportement non défini est que les responsables de mise en œuvre ne sont pas tenus de documenter quoi que ce soit, ni un comportement unique cohérent requis. Nécessitant ces choses l'auraient transformé en comportement défini par la mise en œuvre. Un comportement indéfini signifie que vous ne pouvez pas compter sur le comportement, même quand il semble fonctionner comme vous vous attendez.


Il n'est jamais prudent de supposer que ce que vous lisez à partir d'un fichier est correct, surtout si vous faites le tour du système de type en définissant des bits directement.


En ce qui concerne les systèmes intégrés, je suggérerais d'utiliser des types de données de taille fixe Toujours et d'être très explicite sur l'ordre d'octets. Si votre compilateur / mise en œuvre ne vous fournit pas vous, lancez votre propre en-tête et un tas de trucs de préprocesseur. Jetez un coup d'œil à Prefef.sourceforge.net pour une bonne collection de macros de préprocesseur définies par divers compilateurs.



-1
votes

Répondre aux questions posées, je pense que le comportement va bien et ne devrait pas être un problème dans le monde réel. Comme nous n'avons pas ^^ en C ++, je suggérerais! BOOL ==! Bool comme une technique de comparaison de bool sécuritaire.

De cette façon, chaque valeur non nulle dans la variable Bool sera convertie en zéro et chaque zéro est converti en une valeur non nulle, mais la plupart probablement l'une et la même chose pour toute opération de négation.


1 commentaires

Comment cela s'est-il levé? Et comment! Bool ==! Bool résolvait le problème ici, c'est-à-dire qu'il demande au compilateur de comparer un octet zéro converti en Bool, avec la valeur BOOL vrai et les attentes à être égales.



9
votes
  1. Est-ce que ça va? (Ceci a été testé avec g ++ 4.3.3) Je veux dire, si le compilateur doit être conscient que pendant la comparaison booléenne, toute valeur non nulle pourrait signifier VRAI? LI> ol>

    Toute valeur entières non nulle (ou pointeur non null) représente vrai. Mais lors de la comparaison d'entiers et de bool, le bool est converti en Int avant la comparaison. P>

    1. Connaissez-vous des cas où cette affaire de coin pourrait devenir un véritable problème? (Par exemple, tandis que le chargement binaire des données d'un courant) li> ol> blockQuote>

      C'est toujours un vrai problème. P>

      1. est-ce que ça va? p>

        Je ne sais pas si les spécifications spécifient quoi que ce soit à ce sujet. Un compilateur peut toujours créer un code comme celui-ci: ((A! = 0) && (B! = 0)) || ((A == 0) && (B == 0)) Lorsque cela comparait deux booléens, bien que cela puisse diminuer les performances. P>

        À mon avis, ce n'est pas un bogue, mais un comportement non défini. Bien que je pense que chaque implémentatif devrait indiquer aux utilisateurs comment les comparaisons booléennes sont effectuées dans leur mise en œuvre. P> LI> ol> blockQuote>

        Si nous passons par votre dernier code d'échantillon A et B sont BOOL et défini sur true en attribuant 1 et 2 respectivement (NOE les 1 et 2 disparaissent, ils sont maintenant vrais). P> Donc, rompre votre expression: p> xxx pré>

        donc je m'attendrais toujours à ce que l'expression ci-dessus soit bien définie et toujours vraie. P>

        Mais je ne sais pas comment cela s'applique à votre question initiale. Lors de l'attribution d'un entier à un BOOL, l'entier est converti en BOOL (comme décrit plusieurs fois). La représentation réelle de VRAI n'est pas définie par la norme et pourrait être un modèle de bit qui s'inscrit dans un bool (vous ne pouvez pas assumer un motif de bits en particulier). P>

        Lorsque vous comparez le bool à int. dans un int d'abord puis comparé. p>

        1. n'importe quel cas réel p>

          La seule chose qui apparaît dans mon esprit, si quelqu'un lit des données binaires d'un fichier dans une structure, qui ont des membres BOOL. Le problème pourrait augmenter si le dossier a été effectué avec un autre programme qui a écrit 2 au lieu de 1 à la place du Bool (peut-être parce qu'il a été écrit dans un autre langage de programmation). P>

          Mais cela pourrait signifier une mauvaise pratique de programmation. P> li> ol> blockQuote>

          écrire des données dans un format binaire n'est pas portable sans connaissance.
          Il y a des problèmes de taille de chaque objet.
          Il y a des problèmes de représentation: p>

          • Les entiers (ont une endience) li>
          • float (représentation non définie (((généralement dépend du matériel sous-jacent)) li>
          • bool (la représentation binaire est indéfinie par la norme) li>
          • struct (le rembourrage entre les membres peut différer) li> ul>

            Avec tous ceux-ci, vous devez connaître le matériel sous-jacent et le compilateur. Différents compilateurs ou différentes versions du compilateur ou même un compilateur avec différents drapeaux d'optimisation peuvent avoir des comportements différents pour tout ce qui précède. P>

            Le problème avec Union P>

            struct X
            {
                int  a;
                bool b;
            };
            


0 commentaires