J'ai vu des définitions en C
#define TRUE (1==1)
#define FALSE (!TRUE)
Est-ce nécessaire? Quel est l'avantage de définir simplement TRUE comme 1 et FALSE comme 0?
J'ai vu des définitions en C
#define TRUE (1==1)
#define FALSE (!TRUE)
Est-ce nécessaire? Quel est l'avantage de définir simplement TRUE comme 1 et FALSE comme 0?
Réponses:
Cette approche utilisera le boolean
type réel (et sera résolu en true
et false
) si le compilateur le prend en charge. (spécifiquement, C ++)
Cependant, il serait préférable de vérifier si C ++ est utilisé (via la __cplusplus
macro) et d'utiliser réellement true
et false
.
Dans un compilateur C, cela équivaut à 0
et 1
.
(notez que la suppression des parenthèses cassera cela en raison de l'ordre des opérations)
1==1
est un int
. (voir stackoverflow.com/questions/7687403/… .)
boolean
type?
true
ou false
.
#define TRUE true
et à #define FALSE false
chaque fois qu'il __cplusplus
est défini.
La réponse est la portabilité. Les valeurs numériques de TRUE
et FALSE
ne sont pas importantes. Ce qui est important, c'est qu'une instruction comme if (1 < 2)
évalue à if (TRUE)
et une instruction comme if (1 > 2)
évalue à if (FALSE)
.
Certes, en C, (1 < 2)
évalue 1
et (1 > 2)
évalue à 0
, donc comme d'autres l'ont dit, il n'y a pas de différence pratique en ce qui concerne le compilateur. Mais en laissant le compilateur définir TRUE
et FALSE
selon ses propres règles, vous rendez leur signification explicite aux programmeurs, et vous garantissez la cohérence au sein de votre programme et de toute autre bibliothèque (en supposant que l'autre bibliothèque respecte les normes C ... être surpris).
Un peu d'histoire
Certains BASIC définis FALSE
comme 0
et TRUE
comme -1
. Comme de nombreux langages modernes, ils ont interprété toute valeur non nulle comme TRUE
, mais ils ont évalué les expressions booléennes qui étaient vraies comme -1
. Leur NOT
opération a été mise en œuvre en ajoutant 1 et en retournant le signe, car il était efficace de le faire de cette façon. Donc 'NOT x' est devenu -(x+1)
. Un effet secondaire de ceci est qu'une valeur comme 5
évalue à TRUE
, mais NOT 5
évalue à -6
, qui est aussi TRUE
! Trouver ce genre de bogue n'est pas amusant.
Meilleures pratiques
Étant donné les règles de facto selon lesquelles zéro est interprété FALSE
et toute valeur non nulle est interprétée comme TRUE
, vous ne devez jamais comparer des expressions booléennes à TRUE
ouFALSE
. Exemples:
if (thisValue == FALSE) // Don't do this!
if (thatValue == TRUE) // Or this!
if (otherValue != TRUE) // Whatever you do, don't do this!
Pourquoi? Parce que de nombreux programmeurs utilisent le raccourci pour traiter int
s comme bool
s. Ce ne sont pas les mêmes, mais les compilateurs le permettent généralement. Ainsi, par exemple, il est parfaitement légal d'écrire
if (strcmp(yourString, myString) == TRUE) // Wrong!!!
Cela semble légitime, et le compilateur l'acceptera volontiers, mais il ne fait probablement pas ce que vous voudriez. C'est parce que la valeur de retour de strcmp()
est
0 si yourString == myString
<0 si yourString < myString
> 0 siyourString > myString
Ainsi, la ligne ci-dessus TRUE
ne renvoie que quand yourString > myString
.
La bonne façon de procéder est soit
// Valid, but still treats int as bool.
if (strcmp(yourString, myString))
ou
// Better: lingustically clear, compiler will optimize.
if (strcmp(yourString, myString) != 0)
De même:
if (someBoolValue == FALSE) // Redundant.
if (!someBoolValue) // Better.
return (x > 0) ? TRUE : FALSE; // You're fired.
return (x > 0); // Simpler, clearer, correct.
if (ptr == NULL) // Perfect: compares pointers.
if (!ptr) // Sleazy, but short and valid.
if (ptr == FALSE) // Whatisthisidonteven.
Vous trouverez souvent certains de ces «mauvais exemples» dans le code de production, et de nombreux programmeurs expérimentés ne jurent que par eux: ils fonctionnent, certains sont plus courts que leurs alternatives (pédantiquement?) Correctes, et les idiomes sont presque universellement reconnus. Mais considérez: les «bonnes» versions ne sont pas moins efficaces, elles sont garanties pour être portables, elles passeront même les linters les plus stricts, et même les nouveaux programmeurs les comprendront.
Cela ne vaut-il pas la peine?
(1==1)
n'est pas plus portable que 1
. Les règles propres au compilateur sont celles du langage C, qui est clair et sans ambiguïté sur la sémantique de l'égalité et des opérateurs relationnels. Je n'ai jamais vu un compilateur se tromper.
strcmp
est connue pour être inférieure, égale ou supérieure à 0. Elle n'est pas garantie d'être -1, 0 ou 1 et il y a des plates-formes dans la nature qui ne renvoient pas ces valeurs pour gagner en vitesse de mise en œuvre. Donc, si strcmp(a, b) == TRUE
alors, a > b
mais l'implication inverse pourrait ne pas tenir.
(1==1)
et 1
sont toutes deux des expressions constantes de type int
avec la valeur 1. Elles sont sémantiquement identiques. Je suppose que vous pouvez écrire du code qui s'adresse aux lecteurs qui ne le savent pas, mais où cela se termine-t-il?
L' (1 == 1)
astuce est utile pour définir TRUE
d'une manière transparente pour C, tout en offrant un meilleur typage en C ++. Le même code peut être interprété comme C ou C ++ si vous écrivez dans un dialecte appelé "Clean C" (qui se compile en C ou C ++) ou si vous écrivez des fichiers d'en-tête API qui peuvent être utilisés par les programmeurs C ou C ++.
Dans les unités de traduction C, 1 == 1
a exactement la même signification que 1
; et 1 == 0
a la même signification que 0
. Cependant, dans les unités de traduction C ++, 1 == 1
a type bool
. Ainsi, la TRUE
macro ainsi définie s'intègre mieux dans C ++.
Un exemple de la façon dont il s'intègre mieux est que, par exemple, si la fonction foo
a des surcharges pour int
et pour bool
, alors foo(TRUE)
choisira la bool
surcharge. Si TRUE
est simplement défini comme 1
, alors cela ne fonctionnera pas bien dans le C ++. foo(TRUE)
voudra la int
surcharge.
Bien sûr, C99 a introduit bool
, true
et false
et ceux-ci peuvent être utilisés dans les fichiers d'en-tête qui fonctionnent avec C99 et C.
Toutefois:
TRUE
et au FALSE
fur (0==0)
et (1==0)
à mesure de C99.Si vous travaillez dans un mélange C et le projet de C, et ne veulent pas C99, définir le minuscule true
, false
et au bool
lieu.
#ifndef __cplusplus
typedef int bool;
#define true (0==0)
#define false (!true)
#endif
Cela étant dit, l' 0==0
astuce a été (est?) Utilisée par certains programmeurs même dans du code qui n'a jamais été destiné à interagir avec C ++ de quelque manière que ce soit. Cela n'achète rien et suggère que le programmeur a une mauvaise compréhension du fonctionnement des booléens en C.
Au cas où l'explication C ++ ne serait pas claire, voici un programme de test:
#include <cstdio>
void foo(bool x)
{
std::puts("bool");
}
void foo(int x)
{
std::puts("int");
}
int main()
{
foo(1 == 1);
foo(1);
return 0;
}
Le résultat:
bool
int
Quant à la question des commentaires de savoir comment sont surchargées les fonctions C ++ pertinentes pour la programmation mixte C et C ++. Ceux-ci illustrent simplement une différence de type. Une raison valable de vouloir qu'une true
constante soit bool
compilée en C ++ est pour des diagnostics propres. À ses niveaux d'avertissement les plus élevés, un compilateur C ++ peut nous avertir d'une conversion si nous transmettons un entier en bool
paramètre. Une des raisons d'écrire en Clean C n'est pas seulement que notre code est plus portable (puisqu'il est compris par les compilateurs C ++, pas seulement les compilateurs C), mais nous pouvons bénéficier des avis de diagnostic des compilateurs C ++.
TRUE
différeront sous C ++.
#ifdef __cplusplus
pour exprimer votre intention beaucoup plus clairement.
bool
et int
n'ont pas beaucoup d'importance en pratique, car ils sont implicitement convertibles les uns aux autres (et en C en fait "les mêmes" , notez les guillemets , cependant) et il n'y a pas beaucoup de situations dans lesquelles vous devez vraiment désambuiguer entre les deux. «pas beaucoup» était probablement trop lourd, «beaucoup moins comparé au code utilisant des modèles et la surcharge» aurait peut-être été mieux.
#define TRUE (1==1)
#define FALSE (!TRUE)
est équivalent à
#define TRUE 1
#define FALSE 0
en C.
Le résultat des opérateurs relationnels est 0
ou 1
. 1==1
est garanti pour être évalué 1
et !(1==1)
est garanti pour être évalué 0
.
Il n'y a absolument aucune raison d'utiliser le premier formulaire. Notez que le premier formulaire n'est cependant pas moins efficace car sur presque tous les compilateurs une expression constante est évaluée au moment de la compilation plutôt qu'au moment de l'exécution. Ceci est autorisé selon cette règle:
(C99, 6.6p2) "Une expression constante peut être évaluée pendant la traduction plutôt que pendant l'exécution, et en conséquence peut être utilisée à n'importe quel endroit où se trouve une constante."
PC-Lint émettra même un message (506, valeur constante booléenne) si vous n'utilisez pas de littéral pour TRUE
et de FALSE
macros:
Pour C,
TRUE
doit être défini comme étant1
. Cependant, d'autres langages utilisent des quantités autres que 1, de sorte que certains programmeurs estiment que!0
c'est en toute sécurité.
Aussi en C99, les stdbool.h
définitions des macros booléennes true
et false
utilisent directement des littéraux:
#define true 1
#define false 0
1==1
est garanti d'être évalué à1
if(foo == true)
, qui passera d'une simple mauvaise pratique à un buggy pur et simple.
(x == TRUE)
peut avoir une valeur de vérité différente de x
.
Outre le C ++ (déjà mentionné), un autre avantage concerne les outils d'analyse statique. Le compilateur supprimera toute inefficacité, mais un analyseur statique peut utiliser ses propres types abstraits pour faire la distinction entre les résultats de comparaison et d'autres types d'entiers, de sorte qu'il sait implicitement que TRUE doit être le résultat d'une comparaison et ne doit pas être supposé compatible avec un entier.
De toute évidence, C dit qu'ils sont compatibles, mais vous pouvez choisir d'interdire l'utilisation délibérée de cette fonctionnalité pour aider à mettre en évidence les bogues - par exemple, lorsque quelqu'un pourrait avoir de la confusion &
et / &&
ou il a bafoué sa priorité d'opérateur.
if (boolean_var == TRUE)
par le biais d'une expansion if (boolean_var == (1 == 1))
auquel, grâce aux informations de type améliorées du (1 == 1)
nœud, s'inscrit dans le modèle if (<*> == <boolean_expr>)
.
La différence pratique est nulle. 0
est évalué à false
et 1
est évalué à true
. Le fait que vous utilisiez une expression booléenne ( 1 == 1
) ou 1
, pour définir true
, ne fait aucune différence. Ils sont tous deux évalués int
.
Notez que la bibliothèque standard C fournit un en- tête spécifique pour définir booléens: stdbool.h
.
true
est évalué à 1
et false
est évalué à 0
. C ne connaît pas les types booléens natifs, ce ne sont que des entiers.
int
, avec valeur 0
ou 1
. C a un type booléen réel ( _Bool
, avec une macro bool
définie dans <stdbool.h>
, mais qui n'a été ajoutée qu'en C99, ce qui n'a pas changé la sémantique des opérateurs pour utiliser le nouveau type.
_Bool
<stdbool.h>
#define bool _Bool
1 == 1
être évalué comme int
. Édité.
Nous ne connaissons pas la valeur exacte à laquelle TRUE est égal et les compilateurs peuvent avoir leurs propres définitions. Donc, ce que vous privode est d'utiliser celui interne du compilateur pour la définition. Ce n'est pas toujours nécessaire si vous avez de bonnes habitudes de programmation, mais cela peut éviter des problèmes pour un mauvais style de codage, par exemple:
si ((a> b) == VRAI)
Cela pourrait être un désastre si vous définissez manuellement TRUE comme 1, tandis que la valeur interne de TRUE en est une autre.
>
opérateur donne toujours 1 pour vrai, 0 pour faux. Il n'y a aucune possibilité qu'un compilateur C se trompe. Les comparaisons d'égalité TRUE
et de FALSE
style médiocre; ce qui précède est plus clairement écrit comme if (a > b)
. Mais l'idée que différents compilateurs C peuvent traiter la vérité et le faux différemment est tout simplement incorrecte.
En règle générale, dans le langage de programmation C, 1 est défini comme vrai et 0 est défini comme faux. C'est pourquoi vous voyez assez souvent ce qui suit:
#define TRUE 1
#define FALSE 0
Cependant, tout nombre non égal à 0 serait également évalué à vrai dans une instruction conditionnelle. Par conséquent, en utilisant ce qui suit:
#define TRUE (1==1)
#define FALSE (!TRUE)
Vous pouvez simplement montrer explicitement que vous essayez de jouer la sécurité en rendant faux égal à ce qui n'est pas vrai.
#define TRUE (’/’/’/’)
:;#define FALSE (’-’-’-’)
(extrait de coding-guidelines.com/cbook/cbook1_1.pdf page 871)