====== Vordefinierte Präprozessor-Direktiven (ANSI C) ====== ===== Bedingtes Kompilieren ===== * **#include** Sie binden die angegebene Datei in die aktuelle Source-Datei ein. Es gibt zwei Arten der **#include**-Direktive, nämlich: #include und #include "Datei.h" Die erste Anweisung sucht die Datei im Standard-**Includeverzeichnis** des Compilers, die zweite Anweisung sucht die Datei zuerst im Verzeichnis, in der sich die aktuelle Sourcedatei befindet; sollte dort keine Datei mit diesem Namen vorhanden sein, sucht sie ebenfalls im Standard-Includeverzeichnis. * Weitere Direktiven: #define SYMBOL #define KONSTANTE (Wert) #define MAKRO Ausdruck #undef SYMBOL #ifdef #ifndef #elif #else #endif * **#error** Die **#error**-Direktive wird verwendet, um den Kompilierungsvorgang mit einer (optionalen) **Fehlermeldung** abzubrechen. Syntax: #error Fehlermeldung Die Fehlermeldung muss nicht in Anführungszeichen stehen. * **#if** Mit #if kann ähnlich wie mit **#ifdef** eine bedingte Übersetzung eingeleitet werden, jedoch können hier konstante Ausdrücke ausgewertet werden. #if (DEBUGLEVEL >= 1) # define print1 printf #else # define print1(...) (0) #endif #if (DEBUGLEVEL >= 2) # define print2 printf #else # define print2(...) (0) #endif Der Präprozessorausdruck innerhalb der Bedingung folgt den gleichen Regeln wie Ausdrücke in C, jedoch muss das Ergebnis zum Übersetzungszeitpunkt bekannt sein. * **defined** SYMBOL **defined** ist ein unärer Operator, der in den Ausdrücken der **#if** und **#elif** Direktiven eingesetzt werden kann. #define FOO #if defined FOO || defined BAR #error "FOO oder BAR ist definiert" #endif * **#pragma** Bei den **#pragma**-Anweisungen handelt es sich um compilerspezifische Erweiterungen der Sprache C. Diese Anweisungen steuern meist die Codegenerierung. Sie sind aber zu sehr von den Möglichkeiten des jeweiligen Compilers abhängig, als dass man hierzu eine allgemeine Aussage treffen kann. Quelle: [[http://de.wikibooks.org/wiki/C-Programmierung:_Präprozessor|wikibooks]] ===== Vordefinierte Makros (Predefined Macros) ===== **ANSI**-kompatible Makros: //(unvollständig)// ^ Makroname ^ Bedeutung ^ | %%__LINE__%% | Zeilennummer der aktuellen Zeile in der Programmdatei (integer) | | %%__FILE__%% | Name der Programmdatei (String) | | %%__DATE__%% | Übersetzungsdatum der Programmdatei (String: //Mmm dd yyyy//) | | %%__TIME__%% | Übersetzungszeit der Programmdatei (String: //hh:mm:ss//) | | %%__STDC__%% | Erkennungsmerkmal eines ANSI C-Compilers. Ist die ganz-zahlige Konstante auf den Wert 1 gesetzt, handelt es sich um einen ANSI C-konformen Compiler. | | %%__func__%% | Gibt den Namen der Funktion aus, in der dieses Makro verwendet wird.* | | %%__TIMESTAMP__%% | "mtime" von dem source-File (String: //Ddd Mmm Date hh:mm:ss yyyy//) | GCC: [[https://gcc.gnu.org/onlinedocs/cpp/Predefined-Macros.html|Predefined Macros]] * **[[https://gcc.gnu.org/onlinedocs/cpp/Standard-Predefined-Macros.html|Standard Predefined Macros]]** * [[https://gcc.gnu.org/onlinedocs/cpp/Common-Predefined-Macros.html#Common-Predefined-Macros|Common Predefined Macros]] Pre-defined Compiler Macros: [[https://sourceforge.net/p/predef/wiki/Home/]] **Microsoft**-spezifische Makros: //(unvollständig)// ^ Makroname ^ Bedeutung ^ | %%__cplusplus%% | C++-Code | | %%__FUNCTION__%% | Gibt den Namen der Funktion aus, in der dieses Makro verwendet wird.* | | %%__FUNCDNAME__%%| Gibt //Decorated function name// aus, z.B.: %%?exampleFunction@@YAXXZ%% | | %%__FUNCSIG__%% | Gibt //Function signature// aus, z.B.: %%void __cdecl exampleFunction(void)%% | | %%_MFC_VER%% | Gibt die Version von MFC aus. Zum Beispiel, 0x0700 entspricht MFC Version 7.\\ Hier ist die Auflistung, welche Werte welcher Version des MSVC-Compilers entsprechen:\\ [[https://en.wikipedia.org/wiki/Microsoft_Visual_C%2B%2B#Internal_version_numbering]] | | %%_WIN32%% | Definiert für Win32- und Win64-Anwendungen (immer definiert) | | %%_WIN64%% | Definiert für Win64-Anwendungen | | %%_M_AMD64%% | Definiert für Kompilierungen, die auf x64-Prozessoren abzielen. | | %%_M_ARM%% | Definiert für Kompilierungen, die auf ARM-Prozessoren abzielen. | | %%_M_IX86%% | Definiert für Kompilierungen, die auf x86-Prozessoren abzielen. | | %%_M_X64%% | Definiert für Kompilierungen, die auf x64-Prozessoren abzielen. | :!: Das Makro **%%__func__%%** funktioniert nicht mit allen (pre-)Compiler. Der Compiler von MS VisualStudio 2010 z.B. meldet dieses Makro als //undeclared identifier//. Stattdessen soll das Makro **%%__FUNCTION__%%** verwendet werden. (Hier gehts zu den MS VisualStudio 2010 [[http://msdn.microsoft.com/de-de/library/vstudio/b0084kay(v=vs.100).aspx|Predefined Macros]], oder **Predefined Macros** in VisualStudio 2013 [[https://msdn.microsoft.com/de-de/library/b0084kay(v=vs.120).aspx|deutsch]] bzw. [[https://msdn.microsoft.com/en-us/library/b0084kay(v=vs.120).aspx|Originaltext]]. Weitere Infos unter [[http://blogs.msdn.com/b/reiley/archive/2011/08/12/macro-revisited.aspx|MACRO Revisited]].)\\ Um übergreifenden Code zu schreiben kann man es beispielsweise mit folgender Definition umgehen: #ifndef __func__ #define __func__ __FUNCTION__ #endif :!: Oder alternativ, damit die Makros einheitlich aussehen, ein übergreifendes Makro namens **%%__FUNC__%%** definieren, wie folgt: #if defined _WIN32 || defined _WIN64 #define __FUNC__ __FUNCTION__ #else #define __FUNC__ __func__ #endif #if !defined __FUNC__ #error Define for __FUNC__ expected #endif Hier folgt ein Beispiel zur Verwendung dieser vordefinierten Makros: /* direktiven.c */ #include #include #if defined __STDC__ #define isstd_c() printf("ANSI C Compiler\n") #else #define isstd_c() printf("Kein ANSI C Compiler\n") #endif int main(void) { printf("Zeile %d in Datei %s\n",__LINE__,__FILE__); printf("Übersetzt am %s um %s\n",__DATE__,__TIME__); #line 999 "asdf.c" printf("Zeile %d in Datei %s\n",__LINE__,__FILE__); isstd_c(); /* Ist es ein ANSI C Compiler ? */ return EXIT_SUCCESS; } Ein Beispiel für platformabhängiges Kompilieren: #if defined _WIN64 // Hier kommt Code für Windows 64 Bit (muß unbedingt vor dem "_WIN32"-Zweig stehen!) // ... Text ... #elif defined _WIN32 // Hier kommt Code für Windows 32 Bit // ... Text ... #else // Restlicher Code // ... Text ... #endif Siehe auch: [[EDV:PRG:C:Tipp:Plattform-Makros]] ===== String-Literal-Operator ===== :!: //Zitat (Quelle: [[http://wwwuser.gwdg.de/~kboehm/ebook/26_kap20_w6.html]]):// Noch flexibler wird die Makrodefinition durch die Verwendung des stringbildenden Operator (**#**), der manchmal auch String-Literal-Operator genannt wird. Wenn einem Makroparameter im Substitutionsstring ein # vorangestellt ist, wird das Argument beim Expandieren des Makros in einen String in Anführungszeichen umgewandelt. Wenn Sie also ein Makro wie folgt definieren: #define AUSGEBEN(x) printf(#x) und es mit folgender Anweisung aufrufen: AUSGEBEN(Hallo Mama); wird nach der Expansion daraus die Anweisung: printf("Hallo Mama"); Die vom stringbildenden Operator durchgeführte Umwandlung berücksichtigt auch Sonderzeichen. Wenn es im Argument ein Zeichen gibt, das normalerweise ein Escape-Zeichen benötigt, fügt der #-Operator vor diesem Zeichen einen Backslash ein. Greifen wir dazu noch einmal auf unser obiges Beispiel zurück. Der Aufruf: AUSGEBEN("Hallo Mama"); expandiert demnach zu printf("\"Hallo Mama\""); Ein Beispiel für den #-Operator finden Sie in Listing 20.1. Doch zuvor möchte ich Ihnen noch einen anderen Operator vorstellen, der in Makros verwendet wird, der Verkettungsoperator (**##**). Dieser Operator verkettet oder besser verbindet im Zuge der Makro-Expansion zwei Strings. Er verwendet keine Anführungszeichen und sieht auch keine Sonderbehandlung für Escape-Zeichen vor. Er dient hauptsächlich dazu, C-Quelltext-Sequenzen zu erzeugen. Wenn Sie zum Beispiel folgendes Makro definieren und aufrufen: #define HACKEN(x) funk ## x salat = HACKEN(3)(q, w); wird das Makro, das in der zweiten Zeile aufgerufen wurde, folgendermaßen expandiert: salat = funk3 (q, w); Wie Sie sehen, ist es mit Hilfe des ##-Operators möglich, zwischen dem Aufruf verschiedener Funktionen auszuwählen. Sie programmieren praktisch die Erzeugung des C-Quellcodes. Listing 20.1 zeigt eine Möglichkeit, den #-Operator zu verwenden. __Listing 20.1:__ Der #-Operator in der Makro-Expansion. /* Einsatz des #-Operators in einer Makro-Expansion. */ #include #define AUSGABE(x) printf(#x " gleich %d.\n", x) int main(void) { int wert = 123; AUSGABE(wert); return 0; } Ausgabe: wert gleich 123. Durch die Verwendung des #-Operators in Zeile 5 wird der Variablenname wert bei der Expansion des Makros als String in Anführungszeichen an die Funktion printf() übergeben. Nach der Expansion sieht das Makro AUSGABE wie folgt aus: printf("wert" " gleich %d.", wert ); :!: Kompletes eBook habe ich unter [[http://wwwuser.gwdg.de/~kboehm/ebook/]] entdeckt. ---- EOF