#define TRUE! FALSE vs #define TRUE 1

Mis à part le fait que, depuis c99, stdbool.h existe, lors de la définition de macros pour gérer les types booléens en C existe-t-il une différence entre les éléments suivants?

 #define FALSE 0 #define TRUE 1 // Option 1 #define TRUE !FALSE // Option 2 

D’après l’exemple en direct ici , cela ne semble pas faire de différence. Y a-t-il un avantage technique à l’une ou l’autre option? (N’incluant pas le fait que le deuxième exemple fonctionnerait mieux avec des objects bool c ++.)

ISO C et C99 définissent tous les deux ! ainsi.

Le résultat de l’opérateur de négation logique! est 0 si la valeur de son opérande est différente de 0, 1 si la valeur de son opérande est égale à 0. Le résultat est de type int. L’expression! E est équivalente à (0 == E).

Donc !0 évalué à 1 . Avec un compilateur C conforme aux normes, vos deux options auront le même résultat. De plus, il n’ya aucune pénalité d’exécution, les compilateurs se plieront constamment !0 à 1 au moment de la compilation.


Si vous voulez aller jusqu’au bout de la logique et ne faire aucune hypothèse sur ce qu’est le vrai ou le faux …

 #define TRUE (1==1) #define FALSE (!TRUE) 

Cela a l’avantage d’être toujours vrai, peu importe la langue. Par exemple, dans le shell 0 est généralement considéré comme “vrai” ou “pas comme une erreur”.

Ce genre de chose est un anachronisme à une époque où C n’avait pas de norme convenue. Par exemple, la première édition de Code Complete le préconise à la page 369. Lors de sa publication en 1993, il était probable que votre compilateur C ne soit pas conforme à la norme ISO et que stdbool.h n’existait pas. “Code Complete” est également destiné au programmeur polyglotte travaillant dans de nombreuses langues. Certains, comme Shell et Lisp, définissent la vérité différemment.

Il n’y a aucun avantage à l’option 2, car ! 0 ! 0 est garanti par la norme C pour évaluer à 1.

Définir TRUE de cette manière fait partie de l’alimentation de vieilles sources, sans doute pour essayer de suivre le guide de style qui recommande d’éviter autant que possible les “constantes magiques”.

Pas beaucoup de différence.

#define TRUE 1 a un léger avantage sur #define TRUE !FALSE en ce que 1 est un élément unique non affecté par la priorité de l’opérateur.

!FALSE pourrait être (!FALSE) pour faire face au code mystérieux qui tente d’utiliser ++ -- [] . -> ++ -- [] . -> , qui ont une priorité plus élevée à côté de FALSE .

 #define FALSE 0 #define TRUE 1 // Option 1 #define TRUE !FALSE // Option 2 

Il n’y a pas de différence dans les valeurs. 1 et !0 sont des expressions constantes de type int avec la même valeur, 1 (selon la définition donnée par le standard à la sémantique de l’opérateur ! ).

Il y a une différence possible en ce que la deuxième définition n’est pas correctement parenthèses. N’oubliez pas que le développement de macro est effectué textuellement. Le développement d’une macro non entre parenthèse au milieu d’une expression peut entraîner des problèmes de priorité des opérateurs. J’ai écrit un exemple artificiel ici .

Depuis le unaire ! L’opérateur a une priorité très élevée, vous ne rencontrerez probablement pas de problème. Le seul cas auquel je puisse penser est si vous l’utilisez comme préfixe de l’opérateur d’indexation. Par exemple, étant donné:

 int arr[] = { 10, 20 }; 

L’option 1 donne:

 TRUE[arr] == 20 

tandis que l’option 2 donne:

 TRUE[arr] == 0 

Pour voir pourquoi, rappelez-vous que l’indexation de tableaux est commutative (voir cette question et ma réponse , et que l’opérateur d’indexation [] se lie plus étroitement que !

Les leçons ici sont:

  1. Pour toute macro destinée à être utilisée comme expression, la définition complète de la macro doit être placée entre parenthèses, même si vous ne pouvez pas penser à un cas où cela aurait une importance.

  2. Rester simple. En C, 0 est la seule valeur fausse et 1 est la valeur vraie canonique. (Toute valeur non nulle est “vraie”, mais les opérateurs “booléens” intégrés donnent toujours 0 ou 1 ) opérateur de définir TRUE en termes de FALSE (ou vice versa) n’est qu’une complication inutile.

Utilisez si vous le pouvez. Si vous ne pouvez pas (parce que vous êtes coincé avec un compilateur pré-C99), je recommande ceci:

 typedef enum { false, true } bool; 

Ce n’est pas tout à fait la même chose que _Bool / bool de C99 (les conversions vers ce type bool ne sont pas normalisées à 0 ou 1 ), mais elles sont assez proches pour presque toutes les utilisations.

Dans le langage C, TRUE est correctement défini comme (! FALSE) car, bien que zéro (0) soit FALSE et que FALSE soit égal à zéro (0), toute autre valeur est TRUE. Vous pouvez utiliser presque toutes les variables en tant qu’expression booléenne. Si elle est différente de zéro, la valeur de l’expression est TRUE. Un pointeur NULL est zéro pour cette raison. Il en va de même pour le caractère de fin de chaîne (‘\ 0’). Il y a beaucoup de code écrit pour tirer parti de ce fait. Considérer:

 while ( *d++ = *s++ ); 

La copie se termine lorsque le caractère de fin de chaîne est copié. Cet idiome est très commun. Peu importe les problèmes de taille de la mémoire tampon.

C’est l’une des raisons pour lesquelles il est déconseillé de tester l’égalité avec TRUE si vous ne disposez pas d’un type booléen dédié moderne où les seules valeurs possibles sont TRUE et FALSE. Je vous suggère de prendre l’habitude de tester l’inégalité sur FALSE de toute façon, pour des raisons de sécurité. Vous ne pouvez pas toujours travailler avec le nouveau et shiny.

Ils sont juste pareil.

  • !0 est 1 alors !FALSE est 1

#define TRUE !FALSE n’a aucun avantage technique, bien qu’il existe depuis longtemps et qu’il est apparu souvent.

#define TRUE !FALSE peut être mal compris, on pourrait penser que TRUE représente toutes les valeurs autres que 0 .

  • Seulement 1 est égal à TRUE , d’autres valeurs comme 2 , 3 , 255 … (qui !=0 ) ne sont pas égales à TRUE

Pour éviter ce malentendu , de nombreuses organisations exigent de ne plus utiliser #define TRUE !FALSE ou la comparaison avec TRUE doit être remplacée par !FALSE :

 // Should not if (var_bool == TRUE) { ... } //Should if (var_bool != FALSE) { ... }