Programmieren
 
 
 
 
 
C-Grundkurs
 
 
 
 
 
.. #Präprozessordirektiven
 
 

 
 
 
 
 
In C-Programmen findet man häufig Programmzeilen, die mit dem Zeichen # eingeleitet werden. Ein Beispiel ist die Zeile ..                                  #include <stdio.h>
Hier soll geklärt werden, was es mit diesen Zeilen auf sich hat.
 
 
 
 
 
Die Präprozessoranweisung #
Präprozessordirektiven oder -Anweisungen befinden sich grundsätzlich im Quelltext eines Programms. Sie richten sich aber nicht an die CPU für die der nachfolgende Quelltext bestimmt ist, sondern an das Übersetzerprogramm, das den Quelltext übersetzen soll. Bei C ist das der Compiler in der Assemblersprache der Assembler.

Deren Übersetzungsarbeit kann über die Präprozessordirektiven gesteuert werden und bei der Programmiersprache C beginnen diese Anweisungen alle mit dem Doppelgatter #.
Es sollen hier nicht alle Direktiven vorgestellt werden, denn jeder Compiler bringt neue mit sich, und die kann man aus den Handbüchern oder der Online-Hilfe entnehmen. Einige kehren aber immer wieder, und von denen soll hier kurz berichtet werden.
 
 
 
 
 

 
 
 
#include <Dateiname.h>
#include "Pfadangabe\Dateiname.h"
 
Die am häufigsten auftretende Präprozessordirektive dürfte mit Abstand die Direktive #include sein. Es gibt sie zudem in zwei Ausführungen, einmal mit der spitzen Klammer
< .. > und einmal mit Gänsefüsschen "..".

In beiden Fällen wird das den Quelltext übersetzende Programm, also der Compiler oder der Assembler angewiesen, an der Stelle dieser Direktive eine zweite Quelltextdatei nachzuladen und genau hier in den gerade zu bearbeitenden Quelltext einzufügen.
Nun stellen sich dem Compiler wie dem Entwickler zwei Fragen. Die erste ist, 'Wie finde ich die Datei auf dem Datenträger?' und zweitens 'Was ist in dieser Datei drin?'

.. 'Was ist in dieser Datei drin'
Auf diese Frage geht das Kapitel die Header-, Include- oder Kopfdateien.h ein.

.. 'Wie finde ich diese Datei'
Auf diese Frage gibt es zwei Antworten ..

< .. > Steht der Dateiname zwischen den spitzen Klammern, so sucht das übersetzende Programm (Compiler / Assembler) die angegebene Datei in einem Verzeichnis, welches in seinen Voreinstellungen genannt ist. (siehe das Kapitel zur IDE)

" .. " Bei der Verwendung von Gänsefüßchen muss der Programmierer den gesamten Pfad selber angeben. Also beispielsweise c:\pfad\dateiname.h. Die komplette Pfadangabe kann er sich nur dann sparen, wenn die gesuchte Datei im gleichen Verzeichnis liegt, wie die anderen Quelltexte seines Programms. Um wenig schreiben zu müssen ist es also sinnvoll eigene Headerdateien im gleichen Verzeichnis abzulegen, wie den restlichen Quelltext des Programms.
 
 
 
 
 

 
#define  eine_zeichenfolge  zugewiesene_Zeichenfolge
 
Mit dieser Anweisung kann einer Zeichenfolge, einem Literal, eine zweite Zeichenfolge, also ein zweites Literal zugewiesen werden. Beide müssen durch mindestens ein Freizeichen (SPACE) getrennt sein. Am Ende steht kein Semikolon. Die Zuweisung bringt immer dann Vorteile, wenn sich die erste Zeichenfolge besser merken lässt, als die zugewiesene Zeichenfolge.

Beispiele:
Das Kürzel für den Tastendruck 'Carriage Return' den die [ENTER]-Taste liefert und das mit CR abgekürzt werden kann, lässt sich sicher besser merken, als dessen ASCII-Code 0x0D. Schreibt man in seinem Quelltext die Präprozessorzeile ..                                                                                       #define CR 0x0D

.. dann merkt sich der Compiler, dass er überall dort, wo CR im Programm steht, die Zeichenfolge 0x0D einsetzen soll. Dies tut er dann während der Übersetzung des gesamten Quelltextes, und der Programmierer muss nicht jedesmal in seiner ASCII-Tabelle nachsehen, welcher ASCII-Code dem Carriage Return zugewiesen wurde.

Ein zweites Beispiel wäre die Zuweisung der Zahl 3.1415927 zum Ausdruck PI durch ..
                                                                                       #define PI 3.1415927

Auch hier ist es eindeutig leichter sich den Begriff 'PI' zu merken als die Zahl.

Vom Prinzip her lassen sich mit #define ganze Sätze einer Kurzbezeichnung zuweisen ..
                                           #define hallo "Ich wünsche einen schönen Tag"

Hier wird dem Begriff hallo der komplette, mit Anführungsstrichen versehene String zugeweisen, was in dem Befehl printf (hallo) zu der Bildschirmausgabe..
                                                                          Ich wünsche einen schönen Tag
..führen würde.

Durch diese Eigenschaft, zusammen mit der Möglichkeit der Kurzbezeichnung eine in Klammern eingefügte Parameterliste folgen zu lassen, deren Werte in der Zuweisung eingesetzt werden, lassen sich sogenannte Makros bilden.
 
 
 
 
#define zeichenfolge(parameterliste) Ausdruck mit Parametern
 
Ein Beispiel für ein Makro ist folgende Zuweisung
                                                                                           #define mul(x,y) x*y
Hier wird dem Literal mul(x,y) der Ausdruck x*y zugewiesen. Dabei stellen das x und das y in den Klammern Parameter dar, die an Ausdruck x*y weitergeleitet werden. Eine nachfolgende Zeile im Quelltext die wie folgt lautet ..

                            double z;
                            z = mul(12.4, 3);

.. würde dazu führen, dass das Produkt der Zahlen 12.4*3 berechnet würde, und das Ergebnis wäre in z wiederzufinden.
In der geschilderten Weise lassen sich ganze Programme einem Begriff zuordnen, die man dann als Makro bezeichnet. Der Nachteil besteht darin, dass mit jedem Aufruf des Schlüsselwortes auch das komplette Programm in den Quelltext eingefügt wird. Hier wäre eine C-Funktion in Bezug auf den Umfang des benötigten Speicherraums normalerweise effektiver.
 
 
 
 
 

 
 
#undef eine_zeichenfolge
 
 
Mit dieser Präprozessordirektive wird die Zuordnung eines Literals zu einem anderen wieder rückgängig gemacht. Die Zeichenfolge kann folgend neu belegt werden.
 
 
 
 
 

 
 
#ifdef  zeichenfolge
#ifndef zeichenfolge
#endif
 
 
Mit diesen Präprozessordirektiven kann geprüft werden, ob eine zeichenfolge durch #define bzw. #undef gesetzt ist oder nicht. Diese Möglichkeit wird häufig bei der bedingten Compilierung von Quelltexten eingesetzt und ist in jeder Headerdatei zu finden.

Angenommen, eine Headerdatei.h enthält die Definition einer Funktion, oder die von Variablen und sie würde bei einem größeren Programmen mit #include mehrfach in untergeordnete Programmteilen eingebunden. Dann würde der Compiler Fehlermeldungen herausgeben, sobald der die Funktion ein zweites Mal vorgesetzt bekäme. Er würde etwas von 'Redefinition' faseln. Mit den nachfolgenden Zeilen lässt sich dies unterbinden ..

                            #ifndef _meine_funk_
                            #define _meine_funk_

                            void meine_funktion (void)
                            { .. }

                            #endif

Beim ersten Durchlauf wäre das Literal _meine_funk_ nicht definiert, und der Compiler würde alle Zeilen die folgen, bis #endif, zur Kenntnis nehmen. Zuvor weist ihn die Zeile #define _meine_funk_ jedoch an, das Literal zu definieren.
Beim zweiten Auftreten wäre _meine_funk_ nun definiert, und der Compiler würde alle Zeilen bis #endif überspringen. Er sähe also die Definition der Funktion kein zweites mal und würde sich seine Fehlermeldung verkneifen.

Dieses Vorgehen ist in allen Headerdateien der statischen Bibliothek zu finden, und begründet, warum die mehrfache Benutzung einer Zeile wie #include <stdio.h> zu keinen Fehlermeldungen des Compilers führt. Die Unterstriche bei _meine_funk_ dienen nur dazu ein Literal zu erzeugen, das sich von den typischen Bezeichnern in C abhebt, und er ist das einzige Sonderzeichen, das in C-Bezeichnern auftreten darf.
 

 

 

 

 

 
 
#pragma option -1
 
 
Die Intel CPU 8086 hat während der Jahre ihrer Existenz viele Entwicklungsschritte bis hin zum heutigen Pentium .. 80x86-64Bit .., durchlaufen. Damit einher, ging die Ausstattung der CPU's durch zusätzliche Maschinenbefehle und eine Veränderung der Adressierungsmethode, also der Art und Weise, wie die CPU ihren Speicher erreicht.

Diese obige Anweisung veranlasst den Compiler bei der Übersetzung des Quelltextes, den erweiterten Befehlssatz der 80186 CPU im real mode und nicht die des protected mode zu benutzen. Es wird also ein bestimmter Maschinenbefehlssatz der CPU und eine Adressierungsmethode des Speichers ausgewählt. Bei älteren Compilern ist diese Anweisung unnötig und wird ignoriert. Bei der Erstellung von Programmen für den IPC@CHIP Webserver sollte die Anweisung im Kopf des Quelltextes eingefügt werden, .. wenn die 80186CPU nicht bereits in der Compiler-Voreinstellung ausgewählt wurde.
 
 
#pragma argsused
 
 
Diese Anweisung betrifft nur die nächst folgende Quelltextzeile und erklärt dem Compiler, dass die dort aufgeführten Variablen benutzt werden, auch wenn das für den Compiler nicht ersichtlich ist. So kann die Warnung des Compilers, dass eine Variable nicht benutzt würde, verhindert werden.
 
 
 
 
www..de