C non ha alcun tipo booleano incorporato. Qual è il modo migliore per usarli in C?
C non ha alcun tipo booleano incorporato. Qual è il modo migliore per usarli in C?
Risposte:
Dal meglio al peggio:
Opzione 1 (C99)
#include <stdbool.h>
opzione 2
typedef enum { false, true } bool;
Opzione 3
typedef int bool;
enum { false, true };
Opzione 4
typedef int bool;
#define true 1
#define false 0
Se sei indeciso, vai con # 1!
<stdbool.h>
bool
compilatore scelto possono essere più adatti allo scopo previsto di un valore booleano che all'utilizzo di un int
(ovvero il compilatore può scegliere di implementare un metodo bool
diverso da un int
). Se sei fortunato, potresti anche verificare un tipo più rigoroso al momento della compilazione.
int
per bool
? Questo è uno spreco. Usa unsigned char
. Oppure utilizzare integrato di C _Bool
.
Alcuni pensieri sui booleani in C:
Sono abbastanza vecchio che uso semplicemente int
s come tipo booleano senza typedef o definizioni o enumerazioni speciali per valori true / false. Se segui il mio suggerimento di seguito sul non confrontare mai le costanti booleane, allora devi solo usare 0/1 per inizializzare i flag. Tuttavia, un simile approccio può essere considerato troppo reazionario in questi tempi moderni. In tal caso, si dovrebbe assolutamente usare <stdbool.h>
poiché almeno ha il vantaggio di essere standardizzato.
Qualunque siano le costanti booleane chiamate, usale solo per l'inizializzazione. Mai e poi mai scrivere qualcosa del genere
if (ready == TRUE) ...
while (empty == FALSE) ...
Questi possono sempre essere sostituiti dal più chiaro
if (ready) ...
while (!empty) ...
Si noti che questi possono effettivamente essere ragionevolmente e comprensibilmente letti ad alta voce.
Dai un nome positivo alle tue variabili booleane, ovvero full
invece di notfull
. Quest'ultimo porta a un codice che è difficile da leggere facilmente. Confrontare
if (full) ...
if (!full) ...
con
if (!notfull) ...
if (notfull) ...
Entrambe le prime coppie leggono naturalmente, mentre !notfull
è scomodo da leggere così com'è, e peggiora molto nelle espressioni booleane più complesse.
Argomenti booleani dovrebbero generalmente essere evitati. Considera una funzione definita come questa
void foo(bool option) { ... }
All'interno del corpo della funzione, è molto chiaro cosa significhi l'argomento poiché ha un nome conveniente e, si spera, significativo. Ma i siti di chiamata sembrano
foo(TRUE);
foo(FALSE):
Qui, è essenzialmente impossibile dire cosa significasse il parametro senza sempre guardare la definizione o la dichiarazione della funzione, e peggiora molto non appena si aggiungono ancora più parametri booleani. Lo consiglio anche io
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) { ... }
In entrambi i casi, il sito di chiamata ora sembra
foo(OPT_ON);
foo(OPT_OFF);
che il lettore ha almeno una possibilità di comprendere senza trascinare la definizione di foo
.
a == b
funziona?
a
e b
contando da zero, raccomanderei a > 0 == b > 0
invece. Se insisti nel trarre vantaggio dalla veridicità di valori arbitrari diversi da zero, !!var
il valore booleano 0/1 equivale a var
, quindi potresti scrivere !!a == !!b
, anche se molti lettori lo troveranno confuso.
!a == !b
è anche sufficiente per testare l'uguaglianza, i non zeri diventano zero e gli zeri diventano uno.
!!a
"converti una non booleana in un valore di verità equivalente", mentre leggo !a
come "inverti logicamente la variabile booleana a". In particolare, avrei cercato un motivo specifico per cui si desiderava l'inversione logica.
Un valore booleano in C è un numero intero: zero per falso e diverso da zero per vero.
Vedi anche Tipo di dati booleano , sezione C, C ++, Objective-C, AWK .
Ecco la versione che ho usato:
typedef enum { false = 0, true = !false } bool;
Perché false ha un solo valore, ma un true logico potrebbe avere molti valori, ma la tecnica imposta true per essere ciò che il compilatore utilizzerà per l'opposto di false.
Questo risolve il problema di qualcuno che codifica qualcosa che verrebbe a questo:
if (true == !false)
Penso che saremmo tutti d'accordo sul fatto che questa non è una buona pratica, ma per il costo di una volta di fare "true =! False" eliminiamo quel problema.
[EDIT] Alla fine ho usato:
typedef enum { myfalse = 0, mytrue = !myfalse } mybool;
per evitare la collisione del nome con altri schemi che stavano definendo true
e false
. Ma il concetto rimane lo stesso.
[EDIT] Per mostrare la conversione di numero intero in booleano:
mybool somebool;
int someint = 5;
somebool = !!someint;
Il primo (proprio quello più)! converte il numero intero diverso da zero in uno 0, quindi il secondo (più a sinistra)! converte lo 0 in un myfalse
valore. Lascio che sia un esercizio per il lettore convertire un numero intero zero.
[EDIT] Il mio stile è usare l'impostazione esplicita di un valore in un enum quando il valore specifico è richiesto anche se il valore predefinito sarebbe lo stesso. Esempio: poiché falso deve essere zero, utilizzo false = 0,
anzichéfalse,
true
, false
e bool
sono evidenziate in più di quanto sono valori enum e typedef, al contrario di IDE #defines
, che sono raramente sintassi evidenziata.
gcc -ansi -pedantic -Wall
non dà avvisi, quindi mi fido gcc
; Se questo funziona anche c89
perché dovrebbe funzionare anche per c99
.
!
può solo restituire valori 0
e 1
, quindi true = !false
, assegnerà sempre il valore 1. Questo metodo non fornisce alcuna sicurezza aggiuntiva typedef enum { false, true } bool;
.
if(!value)
), ma tale eccezione non è applicabile in questo caso specifico.
Se stai usando un compilatore C99 ha il supporto integrato per i tipi di bool:
#include <stdbool.h>
int main()
{
bool b = false;
b = true;
}
Cominciando dall'inizio. C, ovvero ISO / IEC 9899 ha avuto un tipo booleano da 19 anni . Questo è un tempo molto più lungo della durata prevista della carriera di programmazione C con parti amatoriali / accademiche / professionali combinate quando si visita questa domanda . Il mio lo supera di appena 1-2 anni. Significa che durante il tempo in cui un lettore medio ha imparato qualcosa su C, C ha effettivamente avuto il tipo di dati booleani .
Per il tipo di dati, #include <stdbool.h>
e use true
, false
e bool
. O non lo si includa, e l'uso _Bool
, 1
e 0
invece.
Ci sono varie pratiche pericolose promosse nelle altre risposte a questo thread. Li affronterò:
typedef int bool;
#define true 1
#define false 0
Questo è un no-no, perché un lettore occasionale - che ha imparato C in questi 19 anni - si aspetterebbe che si bool
riferisca al tipo di dati effettivo bool
e si comporterebbe in modo simile, ma non lo fa! Per esempio
double a = ...;
bool b = a;
Con C99 bool
/ _Bool
, b
sarebbe impostato su false
iff a
era zero e in caso true
contrario. C11 6.3.1.2p1
- Quando un valore scalare viene convertito in
_Bool
, il risultato è 0 se il valore confronta uguale a 0; altrimenti, il risultato è 1. 59)Le note
59) NaNs non confronta uguale a 0 e quindi converte in 1.
Con il typedef
posto, il double
sarebbe costretto a un int
- se il valore del doppio non è nell'intervallo per int
, il comportamento non è definito .
Lo stesso vale naturalmente per se true
e false
fosse stato dichiarato in un enum
.
Ciò che è ancora più pericoloso è dichiarare
typedef enum bool {
false, true
} bool;
poiché ora tutti i valori oltre a 1 e 0 non sono validi e se tale valore fosse assegnato a una variabile di quel tipo, il comportamento sarebbe del tutto indefinito .
Pertanto, se non è possibile utilizzare C99 per qualche motivo inspiegabile, per le variabili booleane è necessario utilizzare:
int
e valori 0
e così 1
come sono ; e fare attentamente conversioni di dominio da qualsiasi altro valore a questi con doppia negazione!!
BOOL
, TRUE
e FALSE
!int
o unsigned int
per contenere un'enumerazione, ma non so nulla nello Standard che provocherebbe un comportamento di un'enumerazione come qualsiasi cosa diversa da un numero intero genere.
typedef enum {
false = 0,
true
} t_bool;
!0 = 1
dallo standard C e !a = 0
per qualsiasi valore diverso da zero di a
. Il problema è che qualsiasi diverso da zero è considerato vero. Quindi se a
e b
sono entrambi "veri", non è necessariamente il caso che `a == b`.
C ha un tipo booleano: bool (almeno per gli ultimi 10 (!) Anni)
Includi stdbool.h e true / false funzionerà come previsto.
bool
di essere una macro che si espande _Bool
. La differenza conta perché puoi #undef
una macro (e questo è permesso, almeno come misura transitoria), ma non puoi untypedef
scrivere un typedef. Tuttavia, non altera la spinta principale del tuo primo commento.
Qualsiasi cosa diversa da zero viene valutata come vera nelle operazioni booleane, quindi potresti semplicemente
#define TRUE 1
#define FALSE 0
e usa le costanti.
Solo un complemento ad altre risposte e alcuni chiarimenti, se ti è permesso usare C99.
+-------+----------------+-------------------------+--------------------+
| Name | Characteristic | Dependence in stdbool.h | Value |
+-------+----------------+-------------------------+--------------------+
| _Bool | Native type | Don't need header | |
+-------+----------------+-------------------------+--------------------+
| bool | Macro | Yes | Translate to _Bool |
+-------+----------------+-------------------------+--------------------+
| true | Macro | Yes | Translate to 1 |
+-------+----------------+-------------------------+--------------------+
| false | Macro | Yes | Translate to 0 |
+-------+----------------+-------------------------+--------------------+
Alcune delle mie preferenze:
_Bool
o bool
? Entrambi vanno bene, ma bool
sembrano migliori della parola chiave _Bool
.bool
e _Bool
sono: false
o true
. L'assegnazione 0
o 1
invece di false
o true
è valida, ma è più difficile da leggere e comprendere il flusso logico.Alcune informazioni dallo standard:
_Bool
non è unsigned int
, ma fa parte del gruppo di tipi interi senza segno . È abbastanza grande da contenere i valori 0
o 1
.bool
true
e false
ma di sicuro non è una buona idea. Questa capacità è considerata obsoleta e verrà rimossa in futuro._Bool
o bool
, se il valore scalare è uguale 0
o confronta ad 0
esso sarà 0
, altrimenti il risultato è 1
: _Bool x = 9;
9
viene convertito in 1
quando assegnato a x
._Bool
è 1 byte (8 bit), in genere il programmatore è tentato di provare a utilizzare gli altri bit, ma non è raccomandato, poiché l'unico dato garantito è che viene utilizzato solo un bit per memorizzare i dati, non come un tipo char
che ha 8 bit disponibili.È possibile utilizzare un carattere o un altro contenitore di piccoli numeri per esso.
Pseudo-codice
#define TRUE 1
#define FALSE 0
char bValue = TRUE;
int
), poiché su alcune architetture si ottiene un notevole impatto sulle prestazioni dovendo decomprimere / mascherare i controlli su queste variabili.
È possibile utilizzare _Bool, ma il valore restituito deve essere un numero intero (1 per true, 0 per false). Tuttavia, si consiglia di includere e usare bool come in C ++, come detto in questa risposta dal forum daniweb , così come questa risposta , da questa altra domanda di StackOverflow:
_Bool: tipo booleano di C99. L'uso di _Bool direttamente è consigliato solo se si mantiene un codice legacy che definisce già le macro per bool, true o false. Altrimenti, quelle macro sono standardizzate nell'intestazione. Includi quell'intestazione e puoi usare bool come faresti in C ++.
Le espressioni condizionali sono considerate vere se sono diverse da zero, ma lo standard C richiede che gli operatori logici stessi restituiscano 0 o 1.
@ Tom: #define VERO! FALSO è cattivo ed è completamente inutile. Se il file di intestazione si fa strada nel codice C ++ compilato, può causare problemi:
void foo(bool flag);
...
int flag = TRUE;
foo(flag);
Alcuni compilatori genereranno un avviso sulla conversione int => bool. A volte le persone lo evitano facendo:
foo(flag == TRUE);
per forzare l'espressione a essere un bool C ++. Ma se #define TRUE! FALSE, si finisce con:
foo(flag == !0);
che finisce per fare un confronto int-to-bool che può comunque attivare l'avvertimento.
Se si utilizza C99, è possibile utilizzare il _Bool
tipo. Non #include
sono necessari. Tuttavia, 1
è necessario trattarlo come un numero intero, dove si trova true
ed 0
è false
.
È quindi possibile definire TRUE
e FALSE
.
_Bool this_is_a_Boolean_var = 1;
//or using it with true and false
#define TRUE 1
#define FALSE 0
_Bool var = TRUE;
#include <stdbool.h>
e usa bool
, true
e false
come vuole lo standard.
Questo è quello che uso:
enum {false, true};
typedef _Bool bool;
_Bool
è un tipo incorporato in C. È inteso per valori booleani.
Puoi semplicemente usare la #define
direttiva come segue:
#define TRUE 1
#define FALSE 0
#define NOT(arg) (arg == TRUE)? FALSE : TRUE
typedef int bool;
E utilizzare come segue:
bool isVisible = FALSE;
bool isWorking = TRUE;
isVisible = NOT(isVisible);
e così via
arg
e l'espressione nel suo complesso: #define NOT(arg) (((arg) == TRUE) ? FALSE : TRUE)
. Tuttavia, sarebbe meglio verificare la falsità (darà la risposta corretta anche se arg
fosse 23 invece di 0 o 1:. #define NOT(arg) (((arg) == FALSE) ? TRUE : FALSE)
Ma l'intera espressione può essere ridotta a #define NOT(arg) (!(arg))
, ovviamente, che produce lo stesso risultato.