cpp (od ) – preprocesor dla języków C i C++. Odpowiada za wstępną obróbkę kodu źródłowego zanim rozpocznie się właściwy proces kompilowania. Jest jednak dość prostym narzędziem i w żaden sposób nie rozpoznaje składni języka przetwarzanego programu.
Opis działania
Dyrektywy preprocesora mogą występować w ogólności w dowolnym miejscu programu, a rozróżnienie ich od reszty kodu źródłowego dokonywane jest poprzez poprzedzenie ich znakiem hash #.
Niektóre z częściej używanych dyrektyw należą: #include - dyrektywa włączająca tekst innego pliku źródłowego w miejscu jej wystąpienia w pliku podlegającym aktualnie przetwarzaniu, przy czym możliwe jest zagłębione występowanie dyrektywy include, #define - definiuje stałe i makroinstrukcje (pseudofunkcje) #undef - usuwa definicje stałej lub makra #if - dyrektywy kompilacji warunkowej #elif - działa podobnie jak else if w języku C #endif - oznacza koniec bloku kompilacji warunkowej #ifdef - znaczy to samo co #if defined(…) #ifndef - znaczy to samo co #if !defined(…) #error - generuje błąd wraz z opisem #line - zmienia numer linii i opcjonalnie nazwę pliku zgłaszaną przez kompilator w komunikatach o błędach i ostrzeżeniach
Dyrektywy preprocesora pozwalają na ukrywanie różnic między różnymi architekturami procesorów, systemami operacyjnymi, kompilatorami a nawet samymi standardami języka. Popularnym zastosowaniem jest też tworzenie uniwersalnych nagłówków dla bibliotek C, które mogą być wstawione bezpośrednio do kodu C i C++. W przypadku tego pierwszego preprocesor wytnie konstrukcję extern.
#ifdef __cplusplus extern "C" { #endif
/* Definicje */
#ifdef __cplusplus } #endif
Innym zastosowaniem jest zabezpieczenie plików nagłówkowych przed wielokrotnym dołączaniem do tego samego projektu. Jeżeli treść pliku nagłówkowego nazwa.h obejmie się instrukcjami:
#ifndef _NAZWA_H_ /* (1) */ #define _NAZWA_H_ /* (2) */
/* Definicje */
#endif /* (3) */
to przy pierwszej próbie dołączenia pliku, kompilator najpierw sprawdzi, czy zdefiniowano stałą _NAZWA_H_ (może ona mieć dowolną nazwę, ten sposób jest jednak dobrym zwyczajem promowanym przez programistów) (1) - jeżeli nie, zostanie ona zdefiniowana (2) i do programu zostanie dołączona treść między (2) i (3), oznaczający koniec części dodawanej tylko przy spełnieniu warunku (1).
Niektóre kompilatory obsługują także konstrukcję #pragma once, która zapobiega ponownemu załączeniu treści całego pliku, w którym została użyta. Metoda ta jednak nie ma oparcia w oficjalnym standardzie. Podobnie, jak wszystkie użycia dyrektywy #pragma, jej ewentualna obsługa jest rozszerzeniem wprowadzonym przez dany kompilator i nie jest przenośna pomiędzy różnymi narzędziami.
Zastosowanie w C++ Brak rozpoznawania składni języka przez preprocesor jest potencjalnym źródłem wielu błędów programistycznych. Z tego powodu w języku C++ dodano wiele elementów mających na celu jego zastąpienie. Część tych rozwiązań została też zaimplementowana w C.
Są to między innymi: Deklaracje stałych (poprzez słowo kluczowe języka const zamiast dyrektywy preprocesora #define) (również w C): const int foo = 5; Szablony (tylko C++): template <typename T> void swap(T &x, T &y) { T tmp = x; x = y; y = tmp; } Kompilacja warunkowa z constexpr zamiast makr #if (tylko C++; ): template <typename T> void printTypeInfo() { if constexpr (std::is_integral_v<T>) { std::cout << "Typ jest liczbą całkowitą.\n"; } else { std::cout << "Typ nie jest liczbą całkowitą.\n";
Funkcje constexpr zamiast makr (tylko C++; C++11): constexpr int abs(int x) { if(x > 0) { return x;
return -x; } Nadal jednak konieczne jest użycie preprocesora do włączania nagłówków bibliotek, chyba że używane są moduły (od ).
Przypisy
Kategoria:C (język programowania) Kategoria:C++