
Preprocesor jest to oddzielna część programu kompilującego, która działa przed prawdziwą kompilacją. Jego zadaniem jest troszkę zmienić kod(tak jak my chcemy) zanim kompilator zacznie go tłumaczyć na kod maszynowy. Do sterowania preprocesorem używa się tzw. dyrektyw preprocesora. Każda dyrektywa zaczyna się znakiem # a kończy wraz z końcem linii, powinna także podświetlić się na zielono(chyba, że mamy przestawioną kolorystykę w kompilatorze).
1) Najczęściej używaną dyrektywą, bez której raczej ani rusz(a przynajmniej byłoby bardzo ciężko) jest #include. Z dyrektywą tą musiałeś zetknąć się już na samym początku programowania, trudno znaleźć projekt(taki powyżej 100 linijek powiedzmy) bez tej dyrektywy. Oto jej wzór:
Jej zadaniem jest dołączenie jakiegoś pliku do naszego programu, czyli rozszerzenie go o zewnętrzne elementy(funkcje, struktury, klasy, definicje zmiennych, itd.), które są napisane w innym pliku, a my możemy użyć ich w naszym programie. Na razie poznałeś dopiero jeden plik, iostream, dzięki niemu możemy obsługiwać operacje wejścia-wyjścia.
Należy jeszcze powiedzieć sobie o różnicy pomiędzy nazwami plików w C++, a C. Otóż w C++ nazwy plików nagłówkowych są bez rozszerzeń, tak jak iostream. Natomiast w C, nazwy plików, pisane są z rozszerzeniem. Teraz piszemy w konsoli, bez rozszerzeń w czystym C++, jednak, gdy będziemy mówić o WinAPI, to będziemy pisać pełne nazwy z rozszerzeniami(tak jak w C), wynika to z tego, że pliki nagłówkowe WinAPI, są pisane pod język C, a nie C++.
Gdy chcemy dobrać się do pliku nagłówkowego, który znajduje się w folderze, w którym jest nasza aplikacja, zamiast <> należy napisać "" ":
2) Dyrektywa #define służy do nadawania wartościom nazw. W gąszczu zmiennych i ich wartości, ciężko wszystko pamiętać, dlatego wymyślono definiowanie nazw dla poszczególnych wartości:
Po #defline piszemy nazwę wartości, robimy spację i podajemy tą wartość.
Powiedzmy, że używamy w programie różnych wartości, np. prędkości dźwięku, po co mamy pamiętać, że wynosi ona 332m/s, skoro wystarczy nazwać tą wartość i możemy w programie używać jej nazwy.
Ta linijka spowoduje wyświetlenie liczby 332, bo pisząc PREDKOSC_DZWIEKU to tak jakbyśmy napisali 332.
Jak wcześniej wspomniałem preprocesor dokonuje zmian w kodzie, właśnie my gdy piszemy program widzimy PREDKOŚĆ_DZWIEKU, ale gdy klikniemy kompilację to najpierw wkracza preprocesor i zmienia wszystkie zdefiniowane nazwy na prawdziwe wartości, i kod po przetłumaczeniu przez preprocesor, jest bez tych zdefiniowanych wartości, taka wartość jest tylko ułatwieniem dla nas, a nie dla komputera. W naszym przykładzie po przetłumaczeniu przez preprocesor linijka z wyświetleniem wyglądałaby tak:
WinAPI jest pełne takich zdefiniowanych wartości, nazywa się je flagami. W C++ także występują:
W którejś z lekcji napisałem, że gdy zwrócimy return 0; to będzie oznaczało dla systemu, że program poprawnie się wykonał, przyznam się, że nie wiem czy dobrze powiedziałem, bo nie pamiętam czy należy zwrócić 1 czy 0, aby oznaczało to, że program dobrze się wykonał. Na szczęście w jednej z bibliotek C++ zdefiniowana jest wartość, która powiadamia system o poprawnym zamknięciu programu. Dzięki niej nie muszę zaprzątać sobie głowy czy trzeba podać 1 czy 0, wystarczy podać EXIT_SUCCESS, a ta definicja zastąpi tą liczbę.
3) Dyrektywy sterujące kompilacją:
Nie będę ich tu opisywał, bo raczej rzadko się z nich korzysta. Służą do kompilowania różnych części kodu, w zależności od warunków.
4) Pozostałe dyrektywy:
Tych praktycznie wogóle się nie używa. Jedynie powiem parę słów na temat #pragma. Otóż dyrektywa ta ustawia opcje kompilatora. Dla każdego kompilatora dyrekywy te mogą być inne, dlatego używanie tego powoduje brak przenośności kodu na inny kompilator, jeżeli inne kompilatory danej opcji nie obsługują.