Vediamo un benchmark interessante che dimostra l'utilità o inutilità nel definire diverse variabili da 1 byte. Chiariamo bene questo aspetto:
- performance: vediamo poi uno studio empirico (media del tempo di esecuzione del codice) per vedere se ci sono o meno differenze fra queste variabili, salvate sia nella memoria centrale (RAM) che nel registro della CPU:
- char
- unsigned char
- _Bool
- bool (con la libreria <stdbool.h>)
- aspetto concettuale: anche a parità di prestazioni, efficienza del codice (di fatto, un byte è sempre un byte), nella nostra immaginazione noi intendiamo un datochar per i caratteri, mentre per valori booleani (quindi 0-1, True-False) siamo più portati ad usare il tipo predefinito _Bool (disponibile da C99 ovvero la versione di C del 1999, poi rimpiazzata da ulteriori versioni fino all'ultimo C23, che verrà rilasciato definitivamente nel 2024) oppure il tipo di dato bool, disponibile includendo la libreria <stdbool.h>. Quando usiamo unsigned char, concettualmente ha poco a che fare con i caratteri, semplicemente per avere maggiore range, "ribaltiamo" il range negativo che non ci serve, raddoppiando quello positivo quindi un dato char anziché fermarsi a 127 (ovvero 28=256, da -128 a +127 e in mezzo lo zero) arriva così a 255 (28-1)
Fatta questa premessa, vediamo prima il codice usato (con l'esempio di char, memorizzato in modo automatico nella RAM, poi ovviamente per i diversi test comparativi si cambia questa piccola parte di codice, eventualmente anche includendo la libreria <stdbool.h>):
#include <stdio.h>
#include <time.h>
//nel caso di bool, includere anche la libreria <stdbool.h>
int main() {
char x; //primo esempio, poi sostituire questa parte
unsigned long int i;
clock_t start = clock();
for(i=0;i<1000000000;i++){
x=1;
}
clock_t end = clock();
printf("%f s\n", (float)(end - start) / CLOCKS_PER_SEC);
return 0;
}
Risultati: tralasciando la questione "concettuale", ovvero che per comodità nostra vogliamo vedere la scritta "bool" in modo tale che noi capiamo che si tratta di un dato booleano, solo 0-1, il risultato è che statisticamente le performance, tempo di esecuzione del codice, sono uguali!
Vediamo infatti i valori medi:
- char: 1,8684511 secondi
- unsigned char: 1,8684982 secondi
- _Bool: 1,8709175 secondi
- bool ( <stdbool.h> ): 1,866391 secondi
- register char: 1,8479869 secondi
- register unsigned char: 1,8447403 secondi
- register _Bool: 1,8448512 secondi
- register bool ( <stdbool.h> ): 1,8466109 secondi
Quindi rispettivamente, i valori per la memoria RAM sono di circa 1,868 secondi per tutti i casi; i valori per il registro CPU sono di circa 1,845 secondi. Ribadiamo, possiamo usare indifferentemente la variabile da 1 byte che preferiamo (per comodità, char o unsigned char, senza dover definire "variabili particolari", supportate o non supportate che siano oppure includere librerie extra).
Vediamo infine risultati in due immagini, una tabella comparativa e due grafici (in cui si vede che le differenze sono davvero irrisorie e dovute ad un minimo di aleatorietà).