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?
c
precompiler
Robert Harvey
la source
la source
#define TRUE (’/’/’/’)
:;#define FALSE (’-’-’-’)
(extrait de coding-guidelines.com/cbook/cbook1_1.pdf page 871)Réponses:
Cette approche utilisera le
boolean
type réel (et sera résolu entrue
etfalse
) 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éellementtrue
etfalse
.Dans un compilateur C, cela équivaut à
0
et1
.(notez que la suppression des parenthèses cassera cela en raison de l'ordre des opérations)
la source
1==1
est unint
. (voir stackoverflow.com/questions/7687403/… .)boolean
type?true
oufalse
.#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
etFALSE
ne sont pas importantes. Ce qui est important, c'est qu'une instruction commeif (1 < 2)
évalue àif (TRUE)
et une instruction commeif (1 > 2)
évalue àif (FALSE)
.Certes, en C,
(1 < 2)
évalue1
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éfinirTRUE
etFALSE
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
comme0
etTRUE
comme-1
. Comme de nombreux langages modernes, ils ont interprété toute valeur non nulle commeTRUE
, mais ils ont évalué les expressions booléennes qui étaient vraies comme-1
. LeurNOT
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 comme5
évalue àTRUE
, maisNOT 5
évalue à-6
, qui est aussiTRUE
! 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 commeTRUE
, vous ne devez jamais comparer des expressions booléennes àTRUE
ouFALSE
. Exemples:Pourquoi? Parce que de nombreux programmeurs utilisent le raccourci pour traiter
int
s commebool
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'écrireCela 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()
est0 si
yourString == myString
<0 si
yourString < myString
> 0 si
yourString > myString
Ainsi, la ligne ci-dessus
TRUE
ne renvoie que quandyourString > myString
.La bonne façon de procéder est soit
ou
De même:
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?
la source
(1==1)
n'est pas plus portable que1
. 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, sistrcmp(a, b) == TRUE
alors,a > b
mais l'implication inverse pourrait ne pas tenir.(1==1)
et1
sont toutes deux des expressions constantes de typeint
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éfinirTRUE
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 que1
; et1 == 0
a la même signification que0
. Cependant, dans les unités de traduction C ++,1 == 1
a typebool
. Ainsi, laTRUE
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 pourint
et pourbool
, alorsfoo(TRUE)
choisira labool
surcharge. SiTRUE
est simplement défini comme1
, alors cela ne fonctionnera pas bien dans le C ++.foo(TRUE)
voudra laint
surcharge.Bien sûr, C99 a introduit
bool
,true
etfalse
et ceux-ci peuvent être utilisés dans les fichiers d'en-tête qui fonctionnent avec C99 et C.Toutefois:
TRUE
et auFALSE
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 aubool
lieu.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:
Le résultat:
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 soitbool
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 enbool
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 ++.la source
TRUE
différeront sous C ++.#ifdef __cplusplus
pour exprimer votre intention beaucoup plus clairement.bool
etint
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.est équivalent à
en C.
Le résultat des opérateurs relationnels est
0
ou1
.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:
PC-Lint émettra même un message (506, valeur constante booléenne) si vous n'utilisez pas de littéral pour
TRUE
et deFALSE
macros:Aussi en C99, les
stdbool.h
définitions des macros booléennestrue
etfalse
utilisent directement des littéraux:la source
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 dex
.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.la source
if (boolean_var == TRUE)
par le biais d'une expansionif (boolean_var == (1 == 1))
auquel, grâce aux informations de type améliorées du(1 == 1)
nœud, s'inscrit dans le modèleif (<*> == <boolean_expr>)
.La différence pratique est nulle.
0
est évalué àfalse
et1
est évalué àtrue
. Le fait que vous utilisiez une expression booléenne (1 == 1
) ou1
, pour définirtrue
, ne fait aucune différence. Ils sont tous deux évaluésint
.Notez que la bibliothèque standard C fournit un en- tête spécifique pour définir booléens:
stdbool.h
.la source
true
est évalué à1
etfalse
est évalué à0
. C ne connaît pas les types booléens natifs, ce ne sont que des entiers.int
, avec valeur0
ou1
. C a un type booléen réel (_Bool
, avec une macrobool
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é commeint
. É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.
la source
>
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 deFALSE
style médiocre; ce qui précède est plus clairement écrit commeif (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:
Cependant, tout nombre non égal à 0 serait également évalué à vrai dans une instruction conditionnelle. Par conséquent, en utilisant ce qui suit:
Vous pouvez simplement montrer explicitement que vous essayez de jouer la sécurité en rendant faux égal à ce qui n'est pas vrai.
la source