ein Kapitel zurück                                           ein Kapitel weiter

Mit '#define' ist es möglich Zeichenketten anzugeben die vor der Übersetzung des Programms gegen andere Zeichenkette ausgetauscht werden sollen. Sie Erinnern sich doch noch an unser Kapitel zuvor in dem ich Ihnen gezeigt habe wie unser Programm übersetzt wird. Auch hier wird durch das Zeichen '#' veranlasst das der Präprozessor erst seine Arbeit verrichtet bevor das Programm vom Compiler in Assembler und dann in Maschinensprache übersetzt wird. Z.B.....

/*Download:def1.c*/
#include <stdio.h>
#define EINS 1

int main()
{
printf("%d",EINS);
return 0;
}

Hier definieren wir eine Konstante Namens 'EINS' mit dem Wert 1. Wenn sie das Programm jetzt übersetzten werden bevor kompiliert wird alle Namen mit 'EINS' im Programm vom Präprozessor in dem Wert 1 umgewandelt. Wenn sie dies nicht verstehen schauen sie sich nochmals das Kapitel zuvor an. Sie müssen die Konstante 'EINS' nicht großschreiben, nur dient dies zur besseren Übersicht. Aber Achtung, folgendes geht nicht...

printf("EINS");

Hier wird der String 'EINS' auf dem Bildschirm ausgegeben. Nicht der Wert 1.

Merken sie sich aber auch das '#define....' - Makros Konstanten sind. Das heißt sie können sie zur Laufzeit des Programms nicht mehr ändern. Nun welchen Vorteil hat es dann? Schauen wir uns mal folgendes Programm an....

/*Download:def2.c*/
#include <stdio.h>
#define DOLLAR 2.0345
#define EURO 0.5123
#define MWST 15


int main()
{
int auswahl,ende=0;
float money,tmp;

do{

printf("\t\tDevisen-Rechner\n");
printf("\t\t---------------\n");
printf("\n\n\t\t Bitte wählen sie :\n\n");
printf("\t\t -1- DM nach Euro\n");
printf("\t\t -2- DM nach Dollar\n");
printf("\t\t -3- Euro nach DM\n");
printf("\t\t -4- Dollar nach DM\n");
printf("\t\t -5- Mehrwertsteuer\n");
printf("\t\t -6- Programmende\n");
printf("\n\t\t Eingabe > ");
scanf("%d",&auswahl);
fflush(stdin); /*Tastaturpuffer löschen*/
printf("\n");
if(auswahl==6)
break; /*beendet unsere do...while Schleife*/
printf("Welcher Betrag soll berrechnet werden : ");
scanf("%f",&money);
printf("\n");

switch(auswahl)
{
case 1: printf("%.4f DM = %.4f Euro\n",money,money*EURO);
break;
case 2: printf("%.4f DM = $%.4f Dollar\n",money,money*DOLLAR);
break;
case 3: printf("%.4f Euro = %.4f DM\n",money,money/EURO);
break;
case 4: printf("$%.4f Dollar = %.4f DM\n",money,money/DOLLAR);
break;
case 5: tmp=money/100*MWST;
printf("mit Mehrwertsteucher : %.4f\n DM",money-tmp);
break;

default:printf("Falsche Eingabe!!! (1-6)\n\n");
break;
}
printf("\n");
}while(1); /*Endlosschleife*/

printf("\t\tBYE - BYE\n");

return 0;
}

Das soll ein kleiner Währungsumrechner sein. In den Zeilen...

#define DOLLAR 2.0345
#define EURO 0.5123
#define MWST 15


...definieren wir die Konstanten für DOLLAR,EURO und MWST. Wenn wir unser Programm nun Übersetzen lassen, bekommen bevor compiliert wird, alle Konstanten im Programm mit dem Namen :DOLLAR,EURO,MWST durch den Präprozessor den Wert der Ihnen zusteht. Das heißt alle Zeichen in unserem Programm mit dem Namen DOLLAR werden durch den Wert 2.0345 ersetzt. Unser Compiler selber kriegt von den '#define DOLLAR....' nichts mehr zu sehen und wenn er unser Programm compiliert steht z.B in der Zeile die wir geschrieben haben...

case 5: tmp=money/100*MWST;

...ist jetzt für den Compiler folgender Wert sichtbar....

case 5: tmp=money/100*15;

Nun noch zu unserem Vorteil von '#define...' . Was machen sie jetzt z.B. wenn sich der Dollar-Kurs, der Euro-Kurs oder sich die Mehrwertssteuer (MWST) verändern. Ohne z.B. '#define EURO 0.5434' müssten sie jetzt im Programm alle Werte mit 0.53434 Suchen und Ändern. So wenn sich jetzt der Kurs von Euro ändert brauchen sie nur die Zeile '#define EURO 0.5434' den Wert ändern und somit ändern bei der nächsten Übersetzung des Programms alle anderen Berechnungen in denen der Wert von Euro benötigt wird.

Mit der '#define' - Anweisung könne sie aber nicht nur Zahlen als Konstanten festlegen. Nun zum nächstes Beispiel....

/*Download:def3.c*/
#include <stdio.h>
#define GANZZAHL int
#define SCHREIB printf(
#define END );
#define EINGABE scanf(
#define ENDESTART return 0;
#define NEUEZEILE printf("\n");
#define START int main()
#define BLOCKANFANG {
#define BLOCKENDE }

START
BLOCKANFANG
GANZZAHL zahl;
SCHREIB "Hallo Welt" END
NEUEZEILE
SCHREIB "Zahleingabe : " END
EINGABE "%d",&zahl END
SCHREIB "Die Zahl war %d",zahl END
ENDESTART
BLOCKENDE

Und Viola wir haben eine eigen Programmiersprache gemacht. Nein, natürlich ändert sich nichts C bleibt C. Wir haben hier nur den Syntax verändert. Anstatt 'int main()' schreiben wir in unserem Programm 'START' oder anstatt 'return 0' nehmen wir hier 'ENDESTART'. Unser Präprozessor ersetzt beim Übersetzen die Pseudo-Sprache von uns wieder in die richtige. Theoretisch könnten wir jetzt eine eigene Headerdatei programmieren und ihn dieser Headerdatei schreiben wir unserer '#define' - Anweisungen. Am besten ich zeige Ihnen wie einfach so etwas geht. Schreiben wir in unserem Editor folgende Zeilen...

/*Download:ifdef.h*/
#ifndef MYSYNTAX_H
#define MYSYNTAX_H

#include <stdio.h>
#define GANZZAHL int
#define SCHREIB printf(
#define END );
#define EINGABE scanf(
#define ENDESTART return 0;
#define NEUEZEILE printf("\n");
#define START int main()
#define BLOCKANFANG {
#define BLOCKENDE }


#endif /*MYSYNTAX_H*/

Speichern sie das ganze mit dem Namen MYSYNTAX.H

Jetzt brauchen wir noch schnell unsere main() - Hauptprogramm....

/*Download:defmain.c*/
#include "MYSYNTAX.H"

START
BLOCKANFANG
GANZZAHL zahl;
SCHREIB "Hallo Welt" END
NEUEZEILE
SCHREIB "Zahleingabe : " END
EINGABE "%d",&zahl END
SCHREIB "Die Zahl war %d",zahl END
ENDESTART
BLOCKENDE

Speichern sie unser Hauptprogramm im dem selben Verzeichnis wo sie auch MYSYNTAX.H gespeichert haben, unter welchen Namen sie auch immer wollen z.B.: meinC.c und übersetzen sie das Programm meinC.c und es müsste funktionieren. Sollten sie die Headerdatei 'MYSYNTAX.H' in einem anderen Verzeichnis als in welches sie unser Hauptprogramm gespeichert haben müssen sie das dem Compiler mitteilen. Wenn die Headerdatei z.B. in '/home/myhome/myheader' ist müssen sie es dem Präprozessor mitteilen mittels....

#include "/home/myhome/myheader/MYSYNTAX.H"

So das war nur mal ein kurzer Anschnitt zu dem Thema eigene 'Header machen'.

Nun haben wir auch noch die Möglichkeit Parameterisierte Makros zu schreiben......

/*Download:def4.c*/
#include <stdio.h>
#define KLEINER_100(x) ((x) < 100)

void klHundert(int zahl)
{
if(KLEINER_100(zahl))
printf("Yep! Die Zahl ist kleiner wie 100!\n");

else
printf("Die Zahl ist grösser wie 100!\n");
}

int main()
{
int b=99;
klHundert(b);
return 0;
}

Unser parametrisiertes Makro erkennen sie daran das unmittelbar nach dem Makronamen eine Klammer folgt.....

#define KLEINER_100(x) ((x) < 100)

Nun haben wir einen formalen Parameter 'x'. Den können sie jetzt auf der rechten Seite des Makros beliebig oft verwenden. Nur sollten sie noch beachten das dieser formale Parameter ebenfalls auf der rechten Seite in Klammern stehen muss. Diese Definition wäre falsch.......

#define KLEINER_100(x) (x < 100)

...da unser Parameter 'x' nicht in runden Klammern steht. Unsere Zeile......

if(KLEINER_100(zahl))

...sieht nach dem Präprozessorlauf, also vor der eigentlichen Compilierung so aus....

if((zahl) < 100)

Weiter häufig eingesetzte Varianten dieser Art sind...

#define MAX(x,y) (((x)<=(y)) ?(y) :(x))>

Hier haben gleich zwei Argumente in dem Parameter. Sie müssen sie nur durch ein Komma trennen. Bei diesem Makro wird die größere der beiden Zahlen ermittelt. Ein weiteres Beispiel wäre....

#define TAUSCHE(x,y)   { \
   int j; \
   j=x; x=y; y=j; \
  }


Mit diesem Makro vertauschen wir zwei Integer - Werte. Bei diesem Beispiel sehen sie das es auch möglich ist das sich ein Makro auch auf mehrere Zeilen erstrecken kann. Sie müssen am Zeilenende nur das '\' -Zeichen hinsetzen.

Man kann auch bei Makrodefinitionen auf früher definierte Namen zurückgreifen......

#define PI 3.1415
#define PI_2 PI*2


...hier definieren wir zuerst PI und in der nächsten Zeile definieren wir den Wert von PI * 2

Es sei aber auch erwähnt das zu lange Makros auf denen häufig Zugegriffen werden muss den Code aufblähen, also das Programm Festplattenplatz braucht als nötig. Wenn die Makros länger sind und sie häufiger darauf Zurückgreifen müssen, sollten man eher eine Funktion schreiben. Beispiel....

/*Download:def5.c*/
#include <stdio.h>

#define AUSGABE printf("Es sei aber auch erwähnt das\
zu lange Makros auf denen häufig\ Zugegriffen werden muss den Code\ aufblähen, also das Programm \ Festplattenplatz braucht als\ nötig. Wenn die Makros länger\ sind und sie häufiger darauf\ Zurückgreifen müssen, sollten man\ eher eine Funktion schreiben.\n")


int main()
{
AUSGABE;
AUSGABE;
AUSGABE;
AUSGABE;
return 0;
}

Dies Programm würde nach dem Präprozessordurchlauf und vor dem Compilerlauf folgendermaßen aussehen....

/*Download:def6.c*/
#include <stdio.h>

int main()
{
printf("Es sei aber auch erwähnt das zu lange Makros auf denen häufig"
"Zugegriffen werden muss den Code aufblähen, also das Programm"
"Festplattenplatz braucht als nötig. Wenn die Makros länger sind"
"und sie häufiger darauf Zurückgreifen müssen, sollten man"
"eher eine Funktion schreiben.\n")
printf("Es sei aber auch erwähnt das zu lange Makros auf denen häufig"
"Zugegriffen werden muss den Code aufblähen, also das Programm"
"Festplattenplatz braucht als nötig. Wenn die Makros länger sind"
"und sie häufiger darauf Zurückgreifen müssen, sollten man"
"eher eine Funktion schreiben.\n");
printf("Es sei aber auch erwähnt das zu lange Makros auf denen häufig"
"Zugegriffen werden muss den Code aufblähen, also das Programm"
"Festplattenplatz braucht als nötig. Wenn die Makros länger sind"
"und sie häufiger darauf Zurückgreifen müssen, sollten man"
"eher eine Funktion schreiben.\n");
printf("Es sei aber auch erwähnt das zu lange Makros auf denen häufig"
"Zugegriffen werden muss den Code aufblähen, also das Programm"
"Festplattenplatz braucht als nötig. Wenn die Makros länger sind"
"und sie häufiger darauf Zurückgreifen müssen, sollten man"
"eher eine Funktion schreiben.\n");
return 0;
}

Bitte bedenken sie dies bei Makros. Und noch was zu define. Die define-Direktive ist eine rein für die Programmiersprache C gedachte Direktive. Ein reiner C++ - Compiler wird define deshalb nicht erkennen. Die meisten Compiler kennen aber sowohl C als auch C++. Dies nur zum Thema falls Sie nur die Grundlagen in C kennen lernen wollen um anschließend mit C++ fortzufahren. Außerdem machen inline-Funktionen Funktionsmakros in C++ überflüssig.

Aufgabe :
Schreiben sie für unser Makro TAUSCHE das wir eben durchgenommen haben eine main() - Funktion dazu die sie aufordert zwei Zahlen einzugeben und diese dann vertauscht wieder ausgibt. Hier geht's zur Lösung!

ein Kapitel zurück          nach oben           ein Kapitel weiter


© 2001,2002 Jürgen Wolf