Tipo Booleano in Linguaggio C
Il linguaggio C considera qualunque valore diverso da zero come vero. Tuttavia, per anni, non è esistito un tipo di dato propriamente booleano. In questo articolo vedremo come rappresentare valori booleani in C89 e in C99.
Valori Booleani in C89
Per anni, nel linguaggio C mancava un tipo propriamente booleano, ossia un tipo di dato in grado di memorizzare un valore vero o falso.
Abbiamo visto che il C considera come vero tutto ciò che è diverso da zero, per cui una soluzione a questo problema è stata quella di adoperare variabili di tipo int
per memorizzare 0
, quindi falso, oppure 1
, quindi vero.
Quindi, ad esempio, una variabile booleana, in gergo tecnico flag, poteva essere rappresentata in C in questo modo:
int flag;
flag = 0; /* falso */
/* ... */
flag = 1; /* vero */
Sebbene questa tecnica funzioni, non è la soluzione più leggibile. Anche perché non è immediatamente chiaro che alla variabile flag
possiamo assegnare solo i valori 0
e 1
e che tali valori rappresentino rispettivamente falso e vero.
Spesso, quindi, nei programmi scritti per i compilatori C89, i programmatori tendevano a definire delle macro semplici con i nomi TRUE
e FALSE
:
#define TRUE 1
#define FALSE 0
Per cui l'assegnamento di variabili booleani assumeva un aspetto molto più leggibile:
int flag;
flag = FALSE; /* falso */
/* ... */
flag = TRUE; /* vero */
Fatto questo, possiamo testare la variabile flag
in un'istruzione if
:
if (flag == TRUE) {
printf("La variabile flag è vera\n");
} else {
printf("La variabile flag è falsa\n");
}
Oppure, in modo più compatto, possiamo scrivere:
if (flag) {
printf("La variabile flag è vera\n");
} else {
printf("La variabile flag è falsa\n");
}
Quest'ultima forma, in particolare, è quella forse più corretta dal momento che, come abbiamo visto, in C qualsiasi valore diverso da zero è considerato vero. Di conseguenza, se per errore alla variabile flag
assegniamo un valore diverso da 0
o 1
, l'istruzione if
funzionerà comunque correttamente.
Analogamente, per testare la falsità di una variabile booleana, possiamo scrivere:
if (!flag) {
printf("La variabile flag è falsa\n");
} else {
printf("La variabile flag è vera\n");
}
In questo caso, l'operatore !
(not) inverte il valore della variabile flag
, quindi se flag
è 0
, !flag
sarà 1
, e viceversa.
Quest'idea di utilizzare int
per rappresentare valori booleani è stata, spesso, portata fino ad un grado successivo in cui si definiscono delle macro per rappresentare il tipo booleano in questo modo:
#define BOOL int
#define TRUE 1
#define FALSE 0
BOOL flag;
flag = FALSE; /* falso */
/* ... */
flag = TRUE; /* vero */
In questo modo si rendeva ancora più esplicito il fatto che la variabile flag
fosse di tipo booleano, anche se in realtà era di tipo int
.
Vedremo nelle prossime lezioni delle tecniche più raffinate per definire un tipo booleano in C, come le enumerazioni e le definizioni di tipi personalizzati.
Valori Booleani in C99 e oltre
La mancanza di un tipo booleano in C è stata definitivamente risolta nello standard C99, che ha introdotto un nuovo tipo di dato chiamato _Bool
.
Nello standard C99, possiamo dichiarare, quindi, una variabile booleana in questo modo:
_Bool flag;
Internamente, una variabile di tipo _Bool
non è altro che un intero, precisamente un unsigned int
. Tuttavia, a differenza di una normale variabile intera, essa può assumere solo i valori 0
e 1
. In generale, se proviamo ad assegnare ad una variabile _Bool
un valore diverso da 0
, il compilatore provvede in automatico ad assegnare il valore 1
.
Ad esempio, possiamo scrivere:
_Bool flag;
flag = 8; /* flag assume il valore 1 */
Essendo, nella pratica, degli interi, è possibile effettuare delle operazioni matematiche su variabili di tipo _Bool
. Tuttavia, è buona norma evitare di farlo, ed usare tali variabili solo per valutare condizioni.
Inoltre, è possibile stampare tali variabili utilizzando il formato %d
:
printf("Il valore di flag è %d\n", flag);
In questo caso il valore di flag
verrà stampato come 1
.
Tipo di dati _Bool
Il tipo di dati _Bool
è un tipo di dato introdotto nello standard C99 per rappresentare valori booleani. Il tipo _Bool
può assumere solo due valori: 0
e 1
, che rappresentano rispettivamente i valori falso e vero.
Il nome dato al tipo di dato _Bool
può sembrare a prima vista strano. Perché, infatti, non usare un nome più semplice come bool
? La risposta è che, quando fu definito lo standard C99, bisognava mantenere la retrocompatibilità con i vecchi programmi scritti per lo standard precedente. Motivo per cui, dato che nei vecchi programmi venivano definiti, con macro, tipi come bool
e true
, si è scelto di utilizzare un nome che non entrasse in conflitto con essi.
Inoltre, lo standard C89 detta che qualunque nome che inizia con un underscore seguito da una lettera maiuscola o da un altro underscore è riservato al compilatore. Per cui, il nome _Bool
è un nome riservato.
Lo standard C99 ha introdotto anche una nuova libreria, <stdbool.h>
, che facilita il lavoro con valori booleani.
In particolare, in essa sono definite tre macro:
bool
, che è un alias per_Bool
; anche se, a partire dallo standard C23 non è più un alias ma un tipo a tutti gli effetti;true
, che è un alias per1
;false
, che è un alias per0
.
Quindi, possiamo scrivere:
#include <stdbool.h>
bool flag;
flag = true; /* vero */
/* ... */
flag = false; /* falso */
In questo modo, il codice risulta più leggibile e più vicino al linguaggio naturale.
Header <stdbool.h>
L'header <stdbool.h>
è un header introdotto nello standard C99 che definisce tre macro per facilitare il lavoro con valori booleani:
bool
, che è un alias per_Bool
;true
, che è un alias per1
;false
, che è un alias per0
.
In Sintesi
- In C89 non esiste un tipo di dato booleano, per cui si utilizzano variabili di tipo
int
per rappresentare valori booleani; - Per rendere il codice più leggibile, si possono definire delle macro
TRUE
eFALSE
per rappresentare rispettivamente i valori1
e0
; - Nello standard C99 è stato introdotto il tipo
_Bool
per rappresentare valori booleani; - Nello standard C99 è stata introdotta la libreria
<stdbool.h>
che definisce tre macro per facilitare il lavoro con valori booleani:bool
,true
efalse
.