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> boolcompilatore 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 booldiverso da un int). Se sei fortunato, potresti anche verificare un tipo più rigoroso al momento della compilazione.
intper 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 ints 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 fullinvece 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 == bfunziona?
ae bcontando da zero, raccomanderei a > 0 == b > 0invece. Se insisti nel trarre vantaggio dalla veridicità di valori arbitrari diversi da zero, !!varil 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 !acome "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 truee 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 myfalsevalore. 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, falsee boolsono evidenziate in più di quanto sono valori enum e typedef, al contrario di IDE #defines, che sono raramente sintassi evidenziata.
gcc -ansi -pedantic -Wallnon dà avvisi, quindi mi fido gcc; Se questo funziona anche c89perché dovrebbe funzionare anche per c99.
!può solo restituire valori 0e 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, falsee bool. O non lo si includa, e l'uso _Bool, 1e 0invece.
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 boolriferisca 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, bsarebbe impostato su false iff a era zero e in caso truecontrario. 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 typedefposto, il doublesarebbe costretto a un int- se il valore del doppio non è nell'intervallo per int, il comportamento non è definito .
Lo stesso vale naturalmente per se truee falsefosse 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:
inte valori 0e così 1 come sono ; e fare attentamente conversioni di dominio da qualsiasi altro valore a questi con doppia negazione!!BOOL, TRUEe FALSE!into unsigned intper 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 = 1dallo standard C e !a = 0per qualsiasi valore diverso da zero di a. Il problema è che qualsiasi diverso da zero è considerato vero. Quindi se ae bsono 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.
booldi essere una macro che si espande _Bool. La differenza conta perché puoi #undefuna macro (e questo è permesso, almeno come misura transitoria), ma non puoi untypedefscrivere 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:
_Boolo bool? Entrambi vanno bene, ma boolsembrano migliori della parola chiave _Bool.boole _Boolsono: falseo true. L'assegnazione 0o 1invece di falseo trueè valida, ma è più difficile da leggere e comprendere il flusso logico.Alcune informazioni dallo standard:
_Boolnon è unsigned int, ma fa parte del gruppo di tipi interi senza segno . È abbastanza grande da contenere i valori 0o 1.bool truee falsema di sicuro non è una buona idea. Questa capacità è considerata obsoleta e verrà rimossa in futuro._Boolo bool, se il valore scalare è uguale 0o confronta ad 0esso sarà 0, altrimenti il risultato è 1: _Bool x = 9; 9viene convertito in 1quando 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 charche 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 _Booltipo. Non #includesono necessari. Tuttavia, 1è necessario trattarlo come un numero intero, dove si trova trueed 0è false.
È quindi possibile definire TRUEe 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, truee falsecome 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 #definedirettiva 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
arge l'espressione nel suo complesso: #define NOT(arg) (((arg) == TRUE) ? FALSE : TRUE). Tuttavia, sarebbe meglio verificare la falsità (darà la risposta corretta anche se argfosse 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.