Rozpoczynamy kolejny rozdział o języku C ⏩. Dowiesz się jak ewoluował logiczny typ danych w języku C (czyli "bool"), zanim powstał jako taki 😮! Wyjaśnię Ci jaką wartością i jakim typem danych charakteryzuje się "prawda" i "fałsz", poza znanym typem logicznym. Poznasz historię powstawania typu "bool" w programowaniu, także "zostań na chwilę i posłuchaj" 📖!
NA POCZĄTKU, LOGICZNY TYP DANYCH W JĘZYKU C JAKO TAKI...NIE ISTNIAŁ!
Możesz sobie myśleć "Co on bredzi za głupoty?! Ja normalnie wstawiam >>bool<< i wszystko działa." 😄.
Mówisz 🙂? To spróbuj nawet w tej chwili skompilować ten program 👇:
#include <stdio.h>
int main(void)
{
bool boolean = true;
printf("%d\n", boolean);
return 0;
}Figa! Błąd kompilacji 😁! Jak mi już wierzysz, to mogę przejść do tłumaczenia o co chodzi, tylko zacznę od samego początku 😊.
NA POCZĄTKU BYŁ "INTEGER"...
Zanim pojawił się jeden z najbardziej kluczowych standardów języka C, C99 (nazwa pochodzi od faktu wdrożenia w 1999 roku 💡), nie było czegoś takiego jak "bool", czy nawet samego hasła "logiczny typ danych" ❌. Ówcześni programiści radzili sobie inaczej 🙂. Teraz możesz twierdzić, że skoro tak, to jak inaczej jesteśmy w stanie rozróżnić zdanie prawdziwe od fałszywego 🤔.
Tak się składa, że jesteśmy w stanie i patrząc na podstawowe typy danych, odpowiedź masz przed samym nosem 😄! Wystarczy Ci typ "int"! Logiczny typ danych w języku C jako liczba całkowita działa tak 👇:
- jeżeli przyjmuje wartość 0 (zero), to jest to fałsz,
- jeżeli przyjmuje wartość różną od zera, to jest to prawda.
Zobacz jak napisałem punkt drugi - "różna od zera", czyli "każda inna poza zerem" 💥! Często spotykałem się z sytuacją, jak ludzie myśleli, że musi być konkretnie wartość 1 (jeden) 1️⃣. Nie! Wystarczy, żeby nie była zerem (a wartość może być dowolna) 😉!
Uwierz mi - nie trzeba niczego więcej, żeby niskim kosztem zdefiniować zachowanie wartości logicznej 😄.
NAGA PRAWDA CZYM JEST "PRAWDA"
Już wiemy jak wtedy stosowało się karykatury logicznego typu danych. Kiedy typ "bool" w języku C jeszcze nie istniał, w ten sam sposób odbywało się ustalanie przejścia przez instrukcję warunkową - również przez liczbę całkowitą 🔢.
"if" w języku C, badając wartość, także zwraca liczbę całkowitą na wyjściu. Działa w następujący sposób 👇:
- gdy dane wyrażenie jest nieprawdziwe, wartością jest 0 (zero),
- gdy dane wyrażenie jest prawdziwe, wartością jest 1 (jeden).
To może być przyczyną dlaczego ludzie często twierdzą, że tylko "jedynka" daje "prawdę", gdy w rzeczywistości tak nie jest 🚫. W elektronice tak, definiując samodzielnie też ta sama wieloletnia konwencja nakazuje robić tak samo.
Natomiast gdy nasz "int" gdy ma "reprezentować prawdę", wystarczy tylko, żeby był różny od zera! Każda inna wartość, nawet zmiennoprzecinkowa, wprowadzona w środek warunku w instrukcji warunkowej, zwróci prawdę, a więc wykona instrukcje umieszczone w bloku ✅. Zatem, o wyborze jednej z wielu ścieżek decyduje "pod maską" liczba całkowita 😮!
PRZYKŁAD KODU ŹRÓDŁOWEGO
Popatrz na ten kod źródłowy i spróbuj ustalić która z instrukcji warunkowych zwróci "prawdę" 👇:
#include <stdio.h>
int main(void)
{
int boolA = 1;
int boolB = 59;
double boolC = 86.32;
float boolD = -100.0f;
int boolE = 0;
if(boolA)
{
printf("%d jest prawdziwe.\n", boolA);
}
if(boolB)
{
printf("%d jest prawdziwe.\n", boolB);
}
if(boolC)
{
printf("%f jest prawdziwe.\n", boolC);
}
if(boolD)
{
printf("%f jest prawdziwe.\n", boolD);
}
if(boolE)
{
printf("%d jest prawdziwe.\n", boolE);
}
return 0;
}Wszystkie wartości z wyjątkiem ostatniej (ponieważ posiada zero) 💡. Tak sobie radzono przed standardem C99 😊.
...POTEM POWSTAŁ TYP "_BOOL"...
Kiedy pojawił się standard C99, logiczny typ danych w języku C zaczął istnieć 🌟! Typ "_Bool" (podłoga przed literą 'B'!) 👇:
_Bool b;to alias powstały przez konstrukcję "typedef" i reprezentuje typ "unsigned int" ("unsigned" oznacza podwojenie maksymalnego zakresu liczby całkowitej bądź zmiennoprzecinkowej kosztem wartości ujemnych ℹ️). "unsigned" dlatego, że liczby ujemne nie są koniecznie potrzebne do uzyskania prawdy/fałszu.
TA NAZWA JEST TAKA JAKAŚ, DZIWNA 🙂
Pierwszy logiczny typ danych w języku C pojawił się jako "_Bool" jako słowo ze znakiem podkreślenia w postaci przedrostek. Wyjaśniam dlaczego się pojawił 🔍.
Przyczyną wstawienia "podłogi" było zminimalizowanie szans na potencjalne kolizje w nazewnictwie. Było ryzyko, że projekty napisane w standardzie ANSI C (1989) mogły stosować słowo "bool" jako nazwy zmiennych. Aby nie stwarzać problemu, członkowie organizacji standaryzacyjnej doszli do wniosku, że wymyślenie przez programistę nazwy "_bool" jako obiektu danych jest zdecydowanie mniej prawdopodobne, niż samo słowo bez przedrostka 💥.
W celu jeszcze większego zredukowania prawdopodobieństwa wystąpienia konfliktu nazw, postanowiono dorzucić wielką literę w słowie "Bool". Tak powstała nazwa "_Bool" 😊. Tyle tytułem historii!
PRZYKŁAD KODU ŹRÓDŁOWEGO
Kolejny przykład kodu, tym razem korzystamy z typu "_Bool". Standardowo nadajemy zmiennym nazwę i przypisujemy...no właśnie, co przypisujemy, jak myślisz 😁? Wartość liczbową czy "true"/"false"?
Typ "_Bool" nie był jeszcze takiej postaci, do jakiej mogłeś(-aś) się przyzwyczaić. Już nie chodzi o nazwę - chodzi o wartości jakie można przypisywać:
_Bool b = 0;Dalej przypisujemy liczby całkowite bądź zmiennoprzecinkowe 🔢! Natomiast, co ciekawe, jedyne dopuszczalne wartości, to 0 (zero) i 1 (jeden). W przypadku podania innej liczby, zostanie zamieniona automatycznie na jedynkę, tak samo jak się to robi w wyrażeniach logicznych w środku instrukcji warunkowych ⚠️.
Podstawmy sobie poznany typ "_Bool" do tych samych wartości, co poprzednio 👇:
#include <stdio.h>
int main(void)
{
_Bool boolA = 1;
_Bool boolB = 59;
_Bool boolC = 86.32;
_Bool boolD = -100.0f;
_Bool boolE = 0;
if(boolA)
{
printf("%d jest prawdziwe.\n", boolA);
}
if(boolB)
{
printf("%d jest prawdziwe.\n", boolB);
}
if(boolC)
{
printf("%d jest prawdziwe.\n", boolC);
}
if(boolD)
{
printf("%d jest prawdziwe.\n", boolD);
}
if(boolE)
{
printf("%d jest prawdziwe.\n", boolE);
}
return 0;
}Po skompilowaniu i uruchomieniu, na jaw wyjdą 2 ciekawe spostrzeżenia, o których uprzedziłem Cię wcześniej 🚨:
- możesz przypisać dowolną liczbę różną od zera (nawet zmiennoprzecinkową) i kompilator nie uzna tego za błąd składniowy,
- typ "_Bool" natychmiast podstawi wprowadzoną wartość pod siebie i przekonwertuje ją sobie na liczbę całkowitą przypisując 0 (zero) lub 1 (jeden, gdy wartość różna od zera).
Po wczytaniu się w komunikaty, zobaczysz same jedynki w miejsca specyfikatorów formatu funkcji "printf" 🔥. Czyli logiczny typ danych w języku C dokonuje automatycznej konwersji do liczby 1, bez względu na to, czy podano liczbę 100, 10000.5 czy -2.8 😱! Nie robi to żadnego problemu dla kompilatora 😮!
Zmęczony(-a) 😉? To nie koniec historii rozwoju typu "bool" 😄!
...AŻ STWORZYLI DO TEGO DYREKTYWĘ!
Przed nami ostatnia część, która będzie w pewnym sensie oferowanym udogodnieniem w kwestii zapisu, do którego zdążyłeś(-aś) się przyzwyczaić 🌟.
W KOŃCU WYDA CI SIĘ ZNAJOME 😁
Teraz pokażę Ci kolejny zapis, a właściwie bibliotekę, która pozwala pisać tak samo, jak w językach wyższej abstrakcji (z podziałem na "true" i "false") 🚀!!! W końcu wynaleziono taki zapis, który panuje obecnie jako najczęściej widziany w wielu innych językach wysokiego poziomu ✨. Aby ominąć ten przedrostek, o którym była mowa poprzednio, dorzucono kolejną możliwość deklarowania logicznego typu danych w sposób pierwotnie ustalony ✔️.
Zostało to opracowane jako rozwiązanie opcjonalne i opakowane w odpowiedni plik nagłówkowy wraz ze źródłowym, aby nie spowodować kolizji nazw już w istniejących programach, natomiast by programiści mogli teraz sami zadecydować czy chcą korzystać z nowoczesnego typu "bool", czy też nie 👍.
Teraz gdy chcesz tworzyć "normalny" logiczny typ danych w języku C 😄 i pisać normalnie "true"/"false", wystarczy tylko dołączyć plik nagłówkowy o nazwie "stdbool.h" przy pomocy dyrektywy "include" 👇:
#include <stdbool.h>i już masz dostęp do (nareszcie) znanego zapisu dla logicznego typu danych 🔓:
bool b = true;Cały czas możesz przypisywać liczby całkowite:
bool b = 1;Jak się domyślasz, tak - to też są aliasy:
bool = _Bool
true = 1
false = 0Także widzisz, że twórcy przez wszystkie etapy "ewolucji" logicznego typu danych robili "opakowania" pod bardziej abstrakcyjne i wygodniejsze dla nas konstrukcje 🧨! Ujmując to dwoma słowami: "lukier składniowy" 🍬. To dlatego kod potrafi "nagle" umożliwić powszechnie występującą nazwę typu danych 🎉!
PRZYKŁAD KODU ŹRÓDŁOWEGO
No i na koniec ostatni przykład na podsumowanie wszystkiego w jedną całość. Zostawiłem część wartości nadal jako liczby, aby pokazać, że nawet jak się uprzemy przy podaniu liczby całkowitej, to nadal nie będzie z tego tytułu żadnych problemów 👇:
#include <stdio.h>
#include <stdbool.h>
int main(void)
{
bool boolA = true;
bool boolB = 59;
bool boolC = 86.32;
bool boolD = -100.0f;
bool boolE = false;
if(boolA)
{
printf("%d jest prawdziwe.\n", boolA);
}
if(boolB)
{
printf("%d jest prawdziwe.\n", boolB);
}
if(boolC)
{
printf("%d jest prawdziwe.\n", boolC);
}
if(boolD)
{
printf("%d jest prawdziwe.\n", boolD);
}
if(boolE)
{
printf("%d jest prawdziwe.\n", boolE);
}
return 0;
}Jeden "include" więcej na samej górze w postaci "stdbool.h" i wygląda to o niebo lepiej 😎! Więcej komentować nie trzeba 🤐.
To była już ostatnia część ukazująca genezę i rozwój logicznego typu danych w języku C. "stdbool.h" to jest ostateczna wersja 🏁.
![]() |
Logiczny typ danych w języku C może być uzyskany na 3 różne sposoby: symulowany przez liczbę całkowitą, poprzez użycie typu "_Bool" bądź poprzez zaimportowanie biblioteki "stdbool.h".
Na tym kończę swój długi wywód o języku C i tajemnicy powstawania typu "bool" 🎯.
