Kapitel 7 Unit 32 von 36 Theorie + Übungen Dauer: ~100 Min.
Ömer
Ömer sagt:

Der Präprozessor ist ein echter Profi-Trick in C! Heute lernt ihr #define für Konstanten und Makros, wie ihr eigene Header-Dateien baut, und wie ihr mit #ifdef Code ein- und ausschalten könnt. Achtung bei den Klammern – da lauert eine fette Falle! 🪤

#define Konstanten lesen & schreiben Makros mit Parametern Klammer-Falle kennen Include Guards schreiben Bedingte Kompilierung nutzen

✏️ Übungen

Übung 1

#define lesen – Was kommt raus?

Gegeben sind folgende #define-Definitionen und Code-Schnipsel. Bestimme jeweils die Ausgabe. Achtung – bei einem Beispiel steckt die Klammer-Falle!

analyse.c C
#define BREITE       8
#define HOEHE        5
#define FLAECHE      (BREITE * HOEHE)
#define QUADRAT_GUT(x)  ((x)*(x))
#define QUADRAT_SCHLECHT(x)  x*x

/* Snippet A */
printf("%d\n", BREITE);

/* Snippet B */
printf("%d\n", FLAECHE);

/* Snippet C */
printf("%d\n", QUADRAT_GUT(3+2));

/* Snippet D – Achtung: Klammer-Falle! */
printf("%d\n", QUADRAT_SCHLECHT(3+2));
SnippetTextersetzung durch PräprozessorAusgabe
A                                                         
B                                                         
C                                                         
D                                                         

Erkläre in einem Satz warum Snippet C und D unterschiedliche Ergebnisse liefern:

Bei Snippet D: schreibe die Textersetzung Schritt für Schritt auf – dann siehst du das Problem sofort.
Übung 2

Konstanten definieren – Mehrwertsteuer-Rechner

Definiere mit #define die folgenden Konstanten und schreibe dann ein Programm, das den Bruttobetrag berechnet und ausgibt.

Das Programm soll ausgeben: Nettopreis: 100.00 EUR und Bruttopreis: 120.00 EUR

#include <stdio.h> /* Deine #define-Konstanten hier: */ int main() { float brutto = PREIS_NETTO * (1.0 + MWST); /* printf-Ausgaben hier: */ return 0; }

Bonusfrage: Könnte man brutto auch als #define schreiben statt als Variable? Wenn ja – wie?

Konvention: #define-Namen immer in GROSSBUCHSTABEN. Kein Semikolon am Ende!
Übung 3

Makro schreiben – ABSOLUT(x)

Schreibe ein Makro ABSOLUT(x), das den Absolutwert einer Zahl zurückgibt. Verwende den ternären Operator ? :. Denke an die Klammern!

Teste dein Makro mit folgenden Werten und schreibe die erwartete Ausgabe auf:

#include <stdio.h> /* Dein ABSOLUT-Makro hier: */ #define ABSOLUT(x) /* ... */ int main() { printf("ABSOLUT(-7) = %d\n", ABSOLUT(-7)); printf("ABSOLUT(5) = %d\n", ABSOLUT(5)); printf("ABSOLUT(0) = %d\n", ABSOLUT(0)); printf("ABSOLUT(-3+1)= %d\n", ABSOLUT(-3+1)); return 0; }

Erwartete Ausgaben (fülle aus):

AufrufErwartete Ausgabe
ABSOLUT(-7)                    
ABSOLUT(5)                    
ABSOLUT(0)                    
ABSOLUT(-3+1)                    
Syntax des ternären Operators: ((x) >= 0 ? (x) : -(x)) – alle Parameter in Klammern!
Übung 4

Bedingte Kompilierung – Debug-Modus

Schreibe ein Programm das eine einfache Berechnung durchführt. Wenn DEBUG definiert ist, sollen zusätzliche Debug-Ausgaben erscheinen. Wenn nicht – nur das Ergebnis.

Implementiere zwei Varianten:

  1. Oben im Code #define DEBUG gesetzt → Debug-Info erscheint
  2. Dieses #define auskommentiert → nur das Ergebnis
#include <stdio.h> #define DEBUG /* Kommentiere das aus für Release-Modus */ int main() { int a = 12; int b = 7; int summe = a + b; int produkt = a * b; /* Debug-Ausgaben nur wenn DEBUG definiert: */ #ifdef DEBUG /* Füge hier Debug-printf ein: */ /* z.B.: printf("[DEBUG] a=%d, b=%d\n", a, b); */ #endif /* Ergebnis immer ausgeben: */ printf("Summe: %d\n", summe); printf("Produkt: %d\n", produkt); return 0; }

Ausgabe MIT DEBUG (schreibe auf was ausgegeben wird):

Ausgabe OHNE DEBUG:

Wie kann man DEBUG beim Kompilieren von außen aktivieren, ohne den Quellcode zu ändern?

#ifdef prüft ob ein Name definiert wurde – egal welchen Wert er hat. gcc -DDEBUG datei.c definiert DEBUG von der Kommandozeile!
Übung 5

Include Guard – Header-Datei schreiben

Schreibe eine Header-Datei rechner.h mit Funktionsdeklarationen für einen einfachen Taschenrechner. Vergiss den Include Guard nicht! Schreibe dann die zugehörige main.c die den Header einbindet.

Datei: rechner.h

/* rechner.h – Deklarationen für Taschenrechner-Funktionen */ /* Include Guard hier einfügen: */ /* Funktionsdeklarationen: */ float addiere(float a, float b); float subtrahiere(float a, float b); float multipliziere(float a, float b); float dividiere(float a, float b); /* Achtung: b != 0! */ /* Ende Include Guard: */

Datei: main.c

#include <stdio.h> /* Eigene Header-Datei einbinden (mit Anführungszeichen!): */ int main() { float x = 10.0, y = 4.0; printf("%.1f + %.1f = %.1f\n", x, y, addiere(x, y)); printf("%.1f - %.1f = %.1f\n", x, y, subtrahiere(x, y)); printf("%.1f * %.1f = %.1f\n", x, y, multipliziere(x, y)); if (y != 0) printf("%.1f / %.1f = %.1f\n", x, y, dividiere(x, y)); return 0; }

Erkläre in einem Satz was passiert, wenn man den Include Guard weglässt und rechner.h aus zwei verschiedenen .c-Dateien eingebunden wird:

Include Guard Schema: #ifndef DATEINAME_H#define DATEINAME_H → Inhalt → #endif. Der Name muss pro Header-Datei eindeutig sein!
Bonus

CLAMP-Makro schreiben

Schreibe ein Makro CLAMP(x, min, max) das einen Wert auf den Bereich [min, max] begrenzt:

Tipp: Du kannst dein MAX- und MIN-Makro kombinieren, oder den ternären Operator zweimal verschachteln.

#include <stdio.h> #define MIN(a,b) ((a)<(b) ? (a) : (b)) #define MAX(a,b) ((a)>(b) ? (a) : (b)) /* Dein CLAMP-Makro hier (nutze MIN und MAX): */ #define CLAMP(x, lo, hi) /* ... */ int main() { /* Teste mit Werten unter, innerhalb und ueber dem Bereich */ printf("CLAMP(-5, 0, 10) = %d\n", CLAMP(-5, 0, 10)); printf("CLAMP( 5, 0, 10) = %d\n", CLAMP( 5, 0, 10)); printf("CLAMP(15, 0, 10) = %d\n", CLAMP(15, 0, 10)); printf("CLAMP( 0, 0, 10) = %d\n", CLAMP( 0, 0, 10)); printf("CLAMP(10, 0, 10) = %d\n", CLAMP(10, 0, 10)); /* Teste mit floats */ float t = 1.5f; printf("CLAMP(1.5, 0.0, 1.0) = %.1f\n", CLAMP(t, 0.0f, 1.0f)); return 0; }

Erwartete Ausgaben (fülle aus):

AufrufErgebnisWarum?
CLAMP(-5, 0, 10)                                           
CLAMP(5, 0, 10)                                           
CLAMP(15, 0, 10)                                           
CLAMP(1.5, 0.0, 1.0)                                           

Wo wird CLAMP in der Praxis eingesetzt? Nenne ein Beispiel aus der echten Programmierung:

CLAMP lässt sich elegant so schreiben: MAX((lo), MIN((x), (hi))) – probiere es aus und erkläre warum das funktioniert!

✅ Selbst-Checkliste Unit 32