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?
3 réponses
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 enint
... §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 quea == 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 quea == 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}}.
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
.
Je comprends que vrai est
#define true 1
mais unbool
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 quea == 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)
Questions connexes
De nouvelles questions
c
C est un langage de programmation à usage général utilisé pour la programmation système (OS et embarqué), les bibliothèques, les jeux et les plateformes multiples. Cette balise doit être utilisée avec des questions générales concernant le langage C, tel que défini dans la norme ISO 9899 (la dernière version, 9899: 2018, sauf indication contraire - également balise les demandes spécifiques à la version avec c89, c99, c11, etc.). C est distinct de C ++ et il ne doit pas être combiné avec la balise C ++ en l'absence d'une raison rationnelle.