854 votes

Utilisation des valeurs booléennes en C

Le C n'a pas de types booléens intégrés. Quelle est la meilleure façon de les utiliser en C ?

90 votes

Le C a un type booléen. Du moins, il y en a un dans les normes les plus récentes.

12 votes

2 votes

Je sais que cette fois-ci, c'était il y a 11 ans, mais MERCI pour avoir posé cette question (et, ci-dessous - répondu) (ainsi que les commentaires ci-dessus !) @neuromancer ! //Best wishes in these corona times.

1258voto

Andreas Bonini Points 15709

Du meilleur au pire :

Option 1 (C99 et plus récent)

#include <stdbool.h>

Option 2

typedef enum { false, true } bool;

Option 3

typedef int bool;
enum { false, true };

Option 4

typedef int bool;
#define true 1
#define false 0

Explication

  • L'option 1 ne fonctionnera que si vous utilisez C99 (ou une version plus récente) et que c'est la "manière standard" de procéder. Choisissez cette option si possible.
  • Les options 2, 3 et 4 auront en pratique le même comportement identique. #Les options 2 et 3 n'utilisent pas les #defines, ce qui à mon avis est mieux.

Si vous êtes indécis, choisissez le numéro 1 !

17 votes

Pouvez-vous élaborer sur pourquoi ce sont les meilleurs et les pires choix ?

5 votes

@endolith L'alignement, les optimisations et la manière de stocker une <stdbool.h> bool que le compilateur choisit peut être plus adapté à l'usage prévu d'une valeur booléenne que l'utilisation d'une fonction int (c'est-à-dire que le compilateur peut choisir d'implémenter une bool différemment d'un int ). Si vous avez de la chance, cela pourrait également entraîner une vérification plus stricte des types au moment de la compilation.

5 votes

Pourquoi utiliser int pour bool ? C'est du gaspillage. Utilisez unsigned char . Ou utilisez la fonction intégrée de C _Bool .

280voto

Dale Hagglund Points 7159

Quelques réflexions sur les booléens en C :

Je suis assez vieux pour utiliser de simples int comme mon type booléen sans aucun typedefs ou définitions spéciales ou enums pour les valeurs vrai/faux. Si vous suivez ma suggestion ci-dessous sur le fait de ne jamais comparer avec des constantes booléennes, alors vous n'avez de toute façon qu'à utiliser 0/1 pour initialiser les drapeaux. Cependant, une telle approche peut être jugée trop réactionnaire en ces temps modernes. Dans ce cas, il faut absolument utiliser <stdbool.h> puisqu'il a au moins l'avantage d'être normalisé.

Quel que soit le nom des constantes booléennes, utilisez-les uniquement pour l'initialisation. N'écrivez jamais quelque chose comme

if (ready == TRUE) ...
while (empty == FALSE) ...

Ceux-ci peuvent toujours être remplacés par les plus clairs

if (ready) ...
while (!empty) ...

Notez qu'il est possible de les lire à haute voix de manière raisonnable et compréhensible.

Donnez à vos variables booléennes des noms positifs, c'est-à-dire full au lieu de notfull . Ce dernier conduit à un code difficile à lire facilement. Comparez

if (full) ...
if (!full) ...

avec

if (!notfull) ...
if (notfull) ...

Les deux premières paires se lisent naturellement, tandis que !notfull est difficile à lire, même telle quelle, et devient bien pire dans les expressions booléennes plus complexes.

Les arguments booléens doivent généralement être évités. Considérons une fonction définie comme suit

void foo(bool option) { ... }

Dans le corps de la fonction, la signification de l'argument est très claire puisqu'il porte un nom pratique et, espérons-le, significatif. Mais, le site d'appel ressemble à

foo(TRUE);
foo(FALSE):

Dans ce cas, il est pratiquement impossible de savoir ce que le paramètre signifie sans toujours regarder la définition ou la déclaration de la fonction, et la situation empire dès que l'on ajoute des paramètres booléens. Je suggère soit

typedef enum { OPT_ON, OPT_OFF } foo_option;
void foo(foo_option option);

o

#define OPT_ON true
#define OPT_OFF false
void foo(bool option) { ... }

Dans les deux cas, le site d'appel ressemble maintenant à ceci

foo(OPT_ON);
foo(OPT_OFF);

que le lecteur a au moins une chance de comprendre sans devoir déterrer la définition de foo .

1 votes

Et comment comparez-vous l'égalité de deux variables ? Ne jamais utiliser de constantes booléennes fonctionne très bien, mais cela ne résout pas le problème de la comparaison avec une variable non constante.

2 votes

Pardonnez-moi, mais je ne comprends pas la question. Demandez-vous comment je compare deux variables booléennes pour l'égalité ? Si oui, est-ce que a == b travail ?

0 votes

Cela ne fonctionne pas car "a" peut avoir la valeur 3, ce qui est vrai, et "b" peut avoir la valeur 5, ce qui est vrai. Mais a == b devrait également être vrai, ce qui n'est pas le cas s'il s'agit d'entiers.

90voto

Fortega Points 8890

Un booléen en C est un entier : zéro pour faux et non-zéro pour vrai.

Voir aussi Type de données booléennes , section C, C++, Objective-C, AWK .

0 votes

Il fonctionne également bien avec les opérateurs logiques (&& et ||).

83voto

Michael Potter Points 821

Voici la version que j'ai utilisée :

typedef enum { false = 0, true = !false } bool;

Parce que false n'a qu'une seule valeur, alors qu'un true logique pourrait avoir plusieurs valeurs, mais la technique définit true comme étant ce que le compilateur utilisera pour l'opposé de false.

Cela résout le problème de quelqu'un qui coderait quelque chose qui se résumerait à cela :

if (true == !false)

Je pense que nous sommes tous d'accord pour dire que ce n'est pas une bonne pratique, mais pour le coût unique de l'utilisation de "true = !false", nous éliminons ce problème.

[Finalement, j'ai utilisé.. :

typedef enum { myfalse = 0, mytrue = !myfalse } mybool;

pour éviter toute collision de noms avec d'autres systèmes qui définissaient true y false . Mais le concept reste le même.

[EDIT] Pour montrer la conversion d'un entier en booléen :

mybool somebool;
int someint = 5;
somebool = !!someint;

Le premier (le plus à droite) ! convertit l'entier non nul en un 0, puis le second (le plus à gauche) ! convertit le 0 en un myfalse valeur. Je laisse au lecteur le soin de convertir un nombre entier nul.

[EDIT] C'est mon style d'utiliser le réglage explicite d'une valeur dans un enum lorsque la valeur spécifique est requise même si la valeur par défaut serait la même. Exemple : Parce que false doit être égal à zéro, j'utilise false = 0, plutôt que false,

7 votes

Un autre avantage de l'utilisation des enums est l'intégration à l'IDE. true , false y bool sont mis en évidence dans la plupart des IDE parce que ce sont des valeurs d'énumération et un typedef, par opposition à #defines qui sont rarement mis en évidence par la syntaxe.

1 votes

Curieux : Sans tenir compte du fait que cela fonctionne ou non, est-il valide en C(99+) de permettre à un enum de faire référence à une valeur antérieure dans le champ de l'enum. même énumération ?

0 votes

@tgm1024 gcc -ansi -pedantic -Wall ne donne aucun avertissement, donc je fais confiance à gcc Si cela fonctionne même pour c89 cela devrait fonctionner pour c99 également.

17voto

mouviciel Points 36624
typedef enum {
    false = 0,
    true
} t_bool;

2 votes

2 à MAX_INT doivent également être évalués à true.

2 votes

@technosaurus Cette approche ne garantit pas que !false == true puisque !false peut être un nombre non nul. Une solution de contournement simple consisterait à affecter explicitement true à !false.

3 votes

@Andrew Ce n'est pas vrai. !0 = 1 par la norme C, et !a = 0 pour toute valeur non nulle de a . Le problème est que toute valeur non nulle est considérée comme vraie. Ainsi, si a y b sont toutes deux "vraies", il n'est pas nécessairement vrai que ` a == b`.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X