|
^ Blog index    << Jak zbudować projekt C++ Buildera pod Eclipse (GNU make)    >> Preprocesor C - szczegóły Preprocessor C - podstawy (preprocesor GNU) 2014-12-16    dr inż. Piotr Romaniuk Spis treści
Działanie preprocesora Preprocesor jest uruchamiany podczas budowania plików w języku C/C++ przed rozpoczęciem kompilacji. Zajmuje się on:
Trzeba pamiętać, że nie rozpoznaje on słów kluczowych języków (C/C++), bo są one kompilowane w następnym etapie. Ponadto całe przetwarzanie odbywa się na zasadzie przetwarzania tekstowego. Ma też ograniczone możliwości przetwarzania wyrażeń, które generalnie sprowadzają się do porównywania wartośći całkowitych.
Bez wątpienia najciekawszym i dającym najwięcej możliwości elementem preprocesora są makrodefinicje.
Pozwalają one zastępować fragmenty tekstu przez inną treść tekstową. Samo przetwarzanie makrodefinicji będzie omówione bardziej
szczegółowo w osobnym opisie .
Sa dwa rodzaje makr z argumentami lub bez nich:
#define MY_TABLE_SIZE 256 #define SATURATE(x) (x>255)? 255 : (x) Uwaga na brak spacji pomiędzy nazwą makra a nawiasem! Wstawienie spacji powoduje, że makro jest identyfikowane przez preprocesor jako bezargumentowe a nawias i jego zawartość staje się częścią rozwinięcia makra: //błędna definicja z powodu spacji po nazwie: #define SATURATE (x) (x>255)? 255 : (x) //wykorzystanie: y = SATURATE(w); //rozwinie się do: y = (x) (x>255)? 255 : (x)(w); //zamiast do oczekiwanego: y = (w>255)? 255 : (w); W przypadku makra z argumentami, podczas jego wykorzystania, należy podać tyle argumentów ile zostało określonych w definicji. Niezgodnośc prowadzi do błędu. #define MACRO(x,y) (x)+(y) w = MACRO(1); //prowadzi do błędu: // error: macro "MACRO" requires 2 arguments, but only 1 given w = MACRO(1,2,3); // error: macro "MACRO" passed 3 arguments, but takes only 2 To oczywiście zaleta, że preprocesor pilnuje zgodności liczby argumentów. Czasem jednak przydatne jest posiadanie nieokreślonej (zmiennej) liczby argumentów. Do tego służy poniższa konstrukcja: #define DBG_MSG(level,format_string,...) printf( "<%d>" format_string, level,__VA_ARGS__ ) Jak widać, zmienną liczbę argumentów oznacza się wielokropkiem. W miejscu gdzie potrzeba je wykorzystać używa się symbolu __VA_ARGS__. Po kilku próbach wykorzystania można natknąc się na problem, gdy format_string jest ostatnim argumentem. W powyższej definicji próba takiego użycia kończy się błędem: error: expected expression before ')' token #define DBG_MSG(level,format_string,...) printf( "<%d>" format_string, level,__VA_ARGS__ ) ^ note: in expansion of macro DBG_MSG DBG_MSG(1, "some_string") ^ Tu z pomocą przychodzi operator konkatenacji (łączenia) w postaci dwóch znaków hash. Zostanie on omówiony poniżej, tutaj jego działanie nalezy rozumieć jako połączenie __VA_ARGS__ z przecinkiem - gdy __VA_ARGS__ jest puste przecinek jest usuwany. #define DBG_MSG(level,format_string,...) printf( "<%d>" format_string, level, ## __VA_ARGS__ )
Zamiana na ciąg tekstowy (stringifikacja)
Preprocesor dostarcza możliwość zamiany argumentu makra na tekst. Przypuśćmy, że potrzebna jest tablica
zawierająca kody błędów oraz ich nazwy, które będą wykorzystywane do wyświetlania komunikatów błędów:
Łączenie ( konkatenacja )
Operator konkatenacji (podwójny znak hash) łączy sąsiadujące tokeny w treści rozwinięcia:
Zaskakujące może być jednak gdy jako argument poda się inny symbol preprocesora.
Okazuje się bowiem, że nie zostanie on przetworzony przed połączeniem a wstawiony "dosłownie".
Aby osiągnąć zamierzony cel, potrzebne jest użycie dodatkowego pośredniczącego makra, które przetworzy argument wejściowy.
|
||||||