Compte tenu du code C11 suivant:

int a = 1234;

bool b = (bool)a; // equivalent to (a != 0) or (a != false) which evaluates to 1 or true

if (a) // equivalent to if(a != 0) or if (a != false) which evaluates to 1 or true
  printf("a\n");

if (a == (bool)true) // should be equivalent to if(!(a == false)) or if (a != false)
  printf("a == (bool)true\n");

Je comprends que true est #define true 1 mais un bool n'est clairement pas un type intégral ordinaire car quelque chose comme (bool)0.1 évalue à 1 tandis qu'un cast en int aboutirait à 0.

1) Pourquoi true n'a-t-il pas été défini comme (bool)1? Cela permettrait au compilateur de générer au moins un avertissement.

2) Pourquoi l'entier de mon exemple n'est-il pas converti en un bool tel que a == (bool)true serait évalué à (bool)a == (bool)true, ce qui serait en fait vrai?

0
xnor 26 nov. 2017 à 21:54

3 réponses

Meilleure réponse

Pourquoi la comparaison avec bool n'est-elle pas convertie en bool en C11?

_Bool est le rang le plus bas et l'opérateur d'égalité == spécifie que ses opérandes _Bool sont promus en int. @StoryTeller


Le rang de _Bool doit être inférieur au rang de tous les autres types d'entiers standard. C11 §6.3.1.1 1

(Opérateurs d'égalité) Si les deux opérandes sont de type arithmétique, les conversions arithmétiques habituelles sont effectuées. §6.5.9 4

(conversions arithmétiques usuelles) ... les promotions d'entiers sont effectuées sur les deux opérandes §6.3.1.8 1

(promotions entières) Si un int peut représenter toutes les valeurs du type d'origine ... la valeur est convertie en int ... §6.3.1.1 2


Les échantillons de code d'OP n'avaient pas de "comparaison avec booléen".

// int compared to int: false since a == 1234 and that is not equal 1
if (a == true)  

Au lieu de cela aurait pu avoir

// int compared to _Bool: false since a == 1234 and that is not equal to 0 or 1
if (a == b) 

Avec int == _Bool, int == short, int == signed char, la même chose se produit. L'opérande de rang inférieur est promu int.


1) Pourquoi true n'était-il pas défini comme (booléen) 1? Cela permettrait au compilateur de générer au moins un avertissement.

Pourquoi? une décision de comité standard il y a des années. Considérer true comme (int)1 plutôt que (_Bool)1 aurait certainement moins impacté le code existant lors de l'introduction de _Bool. (C99). Ceci est cohérent avec les autres sous - int constantes comme SHRT_MAX qui est généralement un int, pas short. Dans tous les cas, dans la plupart des contextes, une promotion vers int/unsigned se produirait de toute façon avant un traitement ultérieur - comme dans ce cas de comparaison.

De plus, (_Bool)1 n'est pas nécessaire pour permettre à un compilateur de fournir un avertissement. Un compilateur peut être créé qui fournit un avertissement à l'aide de divers outils d'analyse. En tant que (_Bool)1, cela simplifierait les choses pour un compilateur de fournir un tel avertissement.

2) Pourquoi l'entier de mon exemple n'est-il pas converti en un bool tel que a == true serait évalué à (bool)a == true, ce qui serait en fait vrai?

Comme true est un (int)1, avec a == true, les deux opérandes sont int. _Bool ne s'applique pas ici.

2) [OP Updated] Pourquoi l'entier de mon exemple n'est-il pas converti en un bool tel que a == true serait évalué à (bool)a == true, ce qui serait en fait vrai?

Le haut de la réponse résout ceci: true dans un int, donc (bool)a est promu int avant la comparaison car int est un rang supérieur à { {X5}}.

4
chux - Reinstate Monica 27 nov. 2017 à 19:53

Résumant les commentaires:

_Bool est en fait "juste" un autre type entier non signé avec la règle exceptionnelle selon laquelle les conversions vers ce dernier aboutissent toujours à 1 ("vrai") si la valeur n'est pas égale à 0 ("faux").

Comme il s'agit d'un entier non signé, les règles de promotion intégrales s'appliquent. Même si true a été défini comme (bool)1 la comparaison a == true aboutit à une comparaison réelle de 1234 == 1 qui est toujours false.

-2
xnor 27 nov. 2017 à 19:51

Je comprends que vrai est #define true 1 mais un bool n'est clairement pas un type intégral ordinaire car quelque chose comme (bool)0.1 donne la valeur 1 tandis qu'un cast en int donnerait 0.

bool (en fait _Bool; bool est une macro qui se développe en _Bool) est un type entier. Il a une caractéristique quelque peu inhabituelle qu'il ne partage avec aucun autre type: la conversion de toute valeur non nulle en _Bool donne 1.

Notez que les opérateurs qui donnent des valeurs logiquement booléennes donnent toujours un résultat int avec la valeur 0 ou 1. Ce n'est généralement pas un problème en raison de conversions implicites.

1) Pourquoi true n'a-t-il pas été défini comme (bool)1? Cela permettrait au compilateur pour au moins émettre un avertissement.

Les compilateurs sont autorisés à produire des avertissements quand ils le souhaitent. Un avertissement sur une comparaison avec true ou false serait une bonne idée.

2) Pourquoi l'entier de mon exemple n'est-il pas converti en bool tel que a == true serait évalué à (bool)a == true ce qui en fait Sois sincère?

a == true doit convertir ses opérandes dans le même type avant de pouvoir les comparer. Cela se fait via les conversions arithmétiques habituelles . Les règles (qui sont assez complexes) sont décrites dans le N1570 section 6.3.1.8. Un résumé très rapide et imprécis est que l'opérande de type plus étroit ( rang de conversion d'entier inférieur ) est converti en le type de l'autre opérande. Par exemple, lorsque vous comparez des expressions de types int et long, l'opérande int est promu en long. _Bool est le type entier le plus étroit, il est donc toujours promu dans une comparaison sauf s'il est comparé à une autre valeur _Bool.

Changer ces règles juste pour _Bool serait déroutant, et cela ne vous achèterait vraiment pas grand-chose.

Conclusion: ne comparez pas les valeurs d'égalité à false ou true. N'écrivez pas:

if (a == true)

Ecrivez:

if (a)

Si c'est ce que tu veux dire. De même, n'écrivez pas:

if (a == false)

Ecrivez

if (!a)
2
Keith Thompson 27 nov. 2017 à 08:43
47499808