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
intper rappresentare valori booleani; - Per rendere il codice più leggibile, si possono definire delle macro
TRUEeFALSEper rappresentare rispettivamente i valori1e0; - Nello standard C99 è stato introdotto il tipo
_Boolper rappresentare valori booleani; - Nello standard C99 è stata introdotta la libreria
<stdbool.h>che definisce tre macro per facilitare il lavoro con valori booleani:bool,trueefalse.