Czy słyszałeś(-aś) o terminie "kompilacja warunkowa" 🤔? Działa bardzo podobnie jak zwykła instrukcja warunkowa z tą różnicą, że tłumaczy odpowiedni fragment kodu źródłowego w zależności od występowania konkretnej dyrektywy ✅. a jego wynik jest przetwarzany na etapie preprocesora! O tym, jak kompilacja warunkowa w języku C wygląda w praktyce i jak z tego korzystać, piszę w środku ✒️.
KOMPILACJA WARUNKOWA W JĘZYKU C. TWORZENIE ZALEŻNOŚCI NA POZIOMIE PREPROCESORA
Zacznijmy od przedstawienia przykładowego scenariusza. Wyobraźmy sobie prostą instrukcję "if", która posiada jakiś konkretny warunek, na przykład 👇:
if(x < 5)
{
// instrukcje
}W środku bloku zostaną wykonane jakieś polecenia. Zawsze będzie to uwzględnione przez kompilator i zawsze będzie występować w pliku wykonywalnym, niezależnie od tego, czy to się spełni, czy nie.
Mamy to 🙂?
To teraz wyobraź sobie, że kompilacja warunkowa w języku C, zamiast instrukcji warunkowej korzysta z dyrektywy, a instrukcje istnieją fizycznie w pliku wykonywalnym (po przetłumaczeniu na kod maszynowy) wtedy i tylko wtedy, gdy stała osadzona jako warunek (pochodząca z dyrektywy "#define") została zdefiniowana ℹ️:
#ifdef CONSTANT
// definicje innych stałych
#endifTym się różni jedno od drugiego 💡!
Do uwarunkowania bloków kodu zależnie od wskazanej stałej (utworzonej za pomocą "#define"), stosujemy 3 hasła:
- "#ifdef" - odpowiednik "if",
- "#else" - odpowiednik "else",
- "#endif" - oznaczenie końca bloku kompilacji warunkowej (tego wyjątkowo nie ma w instrukcji warunkowej 🙂).
Zatem:
- instrukcja warunkowa jest osadzona na stałe w programie, a spełnialność jest sprawdzana w trakcie działania programu,
- kompilacja warunkowa uzależnia osadzenie kodu w programie od występowania wskazanej dyrektywy, a spełnialność jest sprawdzana jeden raz przez preprocesor (podczas "sklejania" programu).
Czyli kompilacja warunkowa jest wykonywana tylko na początku i tylko jeden raz dochodzi do sprawdzenia warunków na etapie działania preprocesora. Instrukcja warunkowa jest w kodzie zawsze i może podlegać wielokrotnym testom (to już zależy od budowy programu) 🧨.
ZASTOSOWANIE
W pytaniu o użyteczność, kompilacja warunkowa w języku C bardzo się przydaje przy zapewnianiu przenośności kodu na wiele platform i systemów ℹ️. Na przykład jakiś projekt może być tworzony pierwotnie pod system Windows, a później, dzięki kompilacji warunkowej, "przeniesiony" na inne platformy ❤️. To pozwala na programowanie wieloplatformowych aplikacji poprzez adaptację obsługi i obchodzenie ograniczeń (bo np. na smartfonie nie masz myszki 😊), natomiast wciąż operujesz na tym samym projekcie - to jest bardzo istotne 🔥!
Potem wystarczy jedynie zmienić odpowiednie stałe dostosowane do odpowiedniej platformy, skompilować kod i tym sposobem uzyskać ten sam produkt, tylko dostosowany pod inną platformę. Dzięki kompilacji warunkowej, staje się możliwe tworzenie przenośnych programów na różne platformy, bez duplikowania kodów źródłowych ⭐!
Operacja przenoszenia znana jest również pod hasłem "portowanie" - jest ono powszechnie stosowane w branży gier (mojej ulubionej 🥰!).
PRZYKŁAD KODU ŹRÓDŁOWEGO
Pora to podsumować prostym kodem źródłowym na do widzenia 😄. Mamy program, który wypisuje odpowiednią treść komunikatu w zależności od zdefiniowanych stałych. Popatrz na niego 👇:
#include <stdio.h>
#ifdef _WIN32
#define MESSAGE "To jest system Windows.\n"
#else
#define MESSAGE "To nie jest system Windows.\n"
#endif
#define NUMBER_SHOULD_BE_EVEN
#ifdef NUMBER_SHOULD_BE_EVEN
#define NUMBER 2
#else
#define NUMBER 1
#endif
int main(void)
{
printf(MESSAGE);
printf("Liczba = %d\n", NUMBER);
return 0;
}U samej góry mamy sporo dyrektyw odpowiadających za kontrolę programu na etapie preprocesora. Dodałem 2 różne "typy": z użyciem stałej występującej w języku i z użyciem stałej niestandardowej.
UŻYCIE WBUDOWANEJ STAŁEJ
To:
#ifdef _WIN32sprawdza czy system operacyjny, na jakim skompilujesz ten program, to system Windows 😊. To jest przykład wykorzystujący jedną z wbudowanych stałych. Dla poszczególnych systemów operacyjnych, obowiązują następujące stałe:
Windows = _WIN32
Mac = __APPLE__ lub __MACH__
Linux = __linux__W zależności od tego, jaki masz system operacyjny, możesz sobie spróbować zamienić na wskazane stałe (nie miałem możliwości przetestować dla Maca i Linuxa, więc uprzedzam, że mogłem popełnić błąd ⚠️!).
Tak czy siak, w zależności od rozstrzygnięcia jaki to system, inna stała otrzyma inną wartość. A co za tym idzie, ujrzymy co innego w funkcji "printf" 💥!
UŻYCIE WŁASNEJ STAŁEJ
To z kolei:
#ifdef NUMBER_SHOULD_BE_EVENjest stała utworzona przeze mnie 😄. Zwróć uwagę, że nie musiałem podawać żadnej wartości!
#define NUMBER_SHOULD_BE_EVENSprawdzamy czy istnieje taka stała zdefiniowana pod podaną nazwą. I znowu - jeżeli tak, to inna stała przyjmie inną wartość, a jeżeli nie, to inną ✔️.
W obu przypadkach, tylko ten jeden raz przed kompilacją, zostanie to zbadane 🚨.
![]() |
Kompilacja warunkowa w języku C to sposób na tworzenie przenośnych aplikacji poprzez warunkowe kompilowanie wskazanych bloków kodu zależnie od występujących stałych przez dyrektywy.
Zakończyliśmy wspólnie wątek kompilacji warunkowej ❤️. Nie będzie to tak często stosowane jak funkcje, aczkolwiek warto znać ten temat, zwłaszcza gdy zaczniesz chcieć pisać programy na kilka różnych platform 🎮.
