B.7    Antworten und Lösungen zu Kapitel 8

  1. Ist die Datei in einfachen Anführungszeichen eingeschlossen (beispielsweise "datei.h"), wird sie im aktuellen Verzeichnis (bzw. im eventuell angegebenen relativen oder absoluten Pfad) gesucht. Wird sie dort nicht gefunden, wird sie im Systemverzeichnis gesucht, wo sich die Header-Dateien im Allgemeinen befinden. Das Verzeichnis zu den Headern kann aber auch mit speziellen Compiler-Flags (abhängig vom Compiler) angegeben werden. Wird die Datei hingegen mit spitzen Klammern eingebunden (beispielsweise <datei.h>), wird nur im Systemverzeichnis des Compilers nach den Header-Dateien gesucht.

  2. Mit der define-Direktive können Sie einen Text angeben, der vor der Übersetzung des Compilers vom Präprozessor durch den dahinterstehenden Ersetzungstext im Quellcode ersetzt wird. Dies wird beispielsweise sowohl für die Definition von symbolischen Konstanten als auch für die Definition von Makros (mit Parametern) verwendet.

  3. Mit der undef-Direktive können Sie definierte symbolische Konstanten oder Makros jederzeit wieder aufheben. Alternativ können Sie auch nur die define-Direktive entfernen. Beachten Sie allerdings: Ab der Stelle, an der Sie mit undef eine Konstante oder ein Makro aufheben, beschwert sich der Compiler, dass ein ungültiger Bezeichner verwendet wird, wenn Sie diesen nach der Zeile mit undef trotzdem noch verwenden.

  4. Die Entscheidung sollte in diesem Fall für die Read-only-Variable mit dem Schlüsselwort const fallen. Würden Sie eine symbolische Konstante mit define verwenden, würde nur an jeder Stelle im Programm, an der VAL verwendet wird, eine textuelle Ersetzung durchgeführt. Während der Programmausführung bedeutet das, dass an dieser Stelle jedes Mal VAL neu berechnet wird. Bei einer const-Variablen findet hingegen die Berechnung nur einmal im Programm statt.

  5. Mit einer bedingten Kompilierung können Sie die Übersetzung eines Programms von Präprozessor-Anweisungen und -Bedingungen abhängig machen. So können Sie beispielsweise entscheiden, auf welchem System ein Quellcode übersetzt wird und welche Header-Dateien oder sonstiger Code inkludiert werden. Zusätzlich vermeiden Sie das Problem, dass ein Header mehrfach inkludiert wird. Eine weitere interessante Lösung für die bedingte Kompilierung dürfte das Debuggen sein.

  6. Wenn Sie die Parameter im Ersatztext des Makros in Zeile (03) in Klammern setzen, sind Sie immer auf der sicheren Seite.

    00  // kap008/loesung001.c
    01 #include <stdio.h>
    02 #include <stdlib.h>
    03 #define MULTI(a, b) ((a)*(b))

    04 int main(void) {
    05 int val1 = 10, val2 = 20;
    06 printf("Multiplikation = %d\n", MULTI(val1, val2-10));
    07 return EXIT_SUCCESS;
    08 }
  7. Die Schleife wird in diesem Beispiel fünfmal durchlaufen. Die erste symbolische Konstante in Zeile (03) wird in Zeile (06) mit der undef-Direktive wieder aufgehoben und in Zeile (07) auf den Wert 5 gesetzt. In Zeile (08) wird dieser Text dann vom Präprozessor ersetzt, sodass die Zeilen (09) und (10) keinen Effekt mehr auf die Schleife haben. Hinter Zeile (10) hat allerdings die symbolische Konstante den Wert 20.

  8. Die Lösung ist einfacher, als Sie vielleicht vermutet haben. Hier ein möglicher Lösungsansatz:

    00  // kap008/mysyntax.h
    01 #ifndef MYSYNTAX_H
    02 #define MYSYNTAX_H
    03 #include <stdio.h>
    04 #include <stdlib.h>

    05 #define MAIN int main(void)
    06 #define OPEN {
    07 #define CLOSE }
    08 #define END return EXIT_SUCCESS;
    09 #define WRITE printf(
    10 #define WRITE_ );

    11 #endif
  9. Hier ein einfacher Lösungsansatz zu den beiden Makros, die mit dem ternären Operator realisiert wurden.

    00  // kap008/loesung002.c
    01 #include <stdio.h>
    02 #include <stdlib.h>
    03 #define MAX(a, b) (((a) > (b)) ? (a) : (b))
    04 #define MIN(a, b) (((a) < (b)) ? (a) : (b))

    05 int main(void) {
    06 int val1 = 20, val2 = 30;
    07 printf("Max. Wert: %d\n", MAX(val1, val2) );
    08 printf("Min. Wert: %d\n", MIN(val1, val2) );
    09 return EXIT_SUCCESS;
    10 }
  10. Auch hier ist die Lösung nicht schwer, weil alle Daten als vordefinierte Standardmakros enthalten sind. Ein möglicher Lösungsansatz lautet:

    00  // kap008/loesung003.c
    01 #include <stdio.h>
    02 #include <stdlib.h>
    03 #define DEBUG_TIME printf("%s / %s\n", __DATE__,__TIME__);
    04 #define DEBUG_LINE printf("%d / %s\n", __LINE__,__FILE__);
    05 #define DEBUG_ALL { DEBUG_TIME DEBUG_LINE }

    06 int main(void) {
    07 DEBUG_ALL;
    08 return EXIT_SUCCESS;
    09 }