CPP (preprocesor)
cpp ( C Preprocessor) jest preprocesorem 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 [edytuj]
Dyrektywy preprocesora mogą występować w ogólności w dowolnym miejscu programu, a rozróżnienie ich reszty kodu źródłowego dokonywane jest poprzez poprzedzenie ich znakiem hash # [1][2].
Do najważniejszych 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
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 następującą konstrukcję:
#pragma once
Zapobiega ona 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++ [edytuj]
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
constzamiast dyrektywy preprocesora#define) (również w C):
const int foo = 5;
- Funkcje rozwijane (inline) zamiast makr (również w C):
inline int abs(int x) { if(x > 0) return x; else return -x; }
- Szablony (tylko C++):
template < class T > void swap(T &x, T &y) { T tmp = x; x = y; y = tmp; }
- Instrukcje warunkowe zamiast kompilacji warunkowej (również w C):
if(1 == 1) printf("1");
Nadal jednak konieczne jest użycie preprocesora do włączania nagłówków bibliotek.
Przypisy
- ↑ Jan Bielecki, Od C do C++, programowanie obiektowe w języku C, Wydawnictwa Naukowo-Techniczne, Warszawa 1990, ISBN 83-204-1332-X
- ↑ Jan Bielecki, Turbo C z grafiką na IBM PC, Wydawnictwa Naukowo-Techniczne, Warszawa 1990, Seria: Mikrokomputery, ISBN 83-204-1101-7