[go: up one dir, main page]

cpp (od ang. C preprocessor) – 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

edytuj

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 #[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 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++

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 const zamiast 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

edytuj
  1. Jan Bielecki: Od C do C++ : programowanie obiektowe w języku C. Warszawa: Wydawnictwa Naukowo-Techniczne, 1990. ISBN 83-204-1332-X. OCLC 830077989. (pol.).
  2. Jan Bielecki: Turbo C z grafiką dla IBM PC. Warszawa: Wydawnictwa Naukowo-Techniczne, 1990, seria: Mikrokomputery. ISBN 83-204-1101-7. OCLC 749636854. (pol.).