C : Interna - Funktionen
In C gibt es nur eine einzige Art von Funktion.
Sie ist folgendermaßen definiert :
return-type function-name( argument declarations )
{
declarations and statements
}
Wichtig ist hier :
"Nested", also verschachtelte Funktionen, wie sie in einigen anderen Programmiersprachen möglich
sind, sind in C NICHT erlaubt.
Weiter will ich erstmal nicht auf spezielle Eigenschaften von Funktionen eingehen. Das hole ich
später nach, versprochen!
Fehler und ihre Behandlung
In Funktionen (wie im gesamten Programm auch) werden Bedingungen auftreten, die zur Laufzeit einen
Fehler provozieren. So etwas kann entweder in der Funktion abgefangen und behandelt werden oder muss
nach außerhalb der Funktion kommuniziert werden.
Zur Anzeige eines Fehlers wird dem aufrufenden Programm ein entsprechender Rückgabewert zur
Verfügung gestellt. Und hier beginnt das Drama!
- Wie soll der Rückgabewert aussehen ?
- Lässt der Typ des Rückgabewerts einen sinnvollen Wert für "Fehler"
überhaupt zu ?
- Wenn ja - wie sieht der aus ?
- Wie lässt der sich mit möglchst wenig Code erkennen ?
- Wenn nein - wie kann der Fehlerfall trotzdem signalisiert werden ?
Erste Erkenntnis
Es ist unabdingbar notwendig, den Rückgabewert jeder Funktion auszuwerten. Dabei darf man sich
NICHT darauf verlassen, daß
der Rückgabewert normal weiterverwendet werden kann, er kann ja auch einen Fehler signalisieren.
Das ist normalerweise ein Wert, der im Zusammenhang mit der Funktion eine Weiterverarbeitung sinnlos
macht und dadurch zu unerwartetem Verhalten führt. Unter Umständen resultiert daraus sogar
ein Absturz des Programms.
Zweite Erkenntnis
Es kann durchaus sinnvoll sein, den Rückgabewert einer Funktion ausschließlich zum
Signalisieren eines Fehlerszustands einzusetzen. Das Ergebnis der Funktion wird dann über
eine Zeigervariable (Referenz) zurückgegeben.
Dritte Erkenntnis
Das Interface einer Funktion ist unbedingt vollständig und sorgfältig zu dokumentieren! Nur
so lassen sich Fehler bei der Verwendung wenigstens ansatzweise verhindern.
Variable Parameter-Liste
Hier geht es um etwas, das besonders aus der printf-Funktion bekannt ist : Implementieren und Aufruf
einer Funktion mit einer Liste von Parametern, von der weder die Anzahl der Parameter noch deren Typ
bekannt ist.
Eigentlich scheint das in "C" ja nicht vorgesehen zu sein - ist es auch nicht. In der
C-Standard-Bibliothek hat man sich aber die Mühe gemacht, dafür eine Schnittstelle zu
implementieren.
Die folgende Funktion ist nur ein Beispiel, wichtig darin sind die Aufrufparameter und der Umgang
damit.
#include <stdarg.h>
void function( int first, ... )
{
double second;
char third;
long int * p_forth;
va_list arg_list;
va_start(arg_list, first);
second = va_arg(arg_list, double);
third = va_arg(arg_list, char);
p_forth = va_arg(arg_list, long int *);
va_end(arg_list);
}
Die drei Punkte ... bezeichnen die in Typ und Anzahl variablen Parameter.
Davor muss mindestes ein Parameter mit Name und Typ angegeben sein.
Für die weitere Verarbeitung der unbekannten Parameter sind ein Typ und drei Makros verantwortlich,
die in der HeaderDatei stdarg.h definiert sind :
- va_list
- void va_start(va_list arg_list, first);
- type va_arg(va_list arg_list, type);
- void va_end(va_list arg_list);
va_list
In einer Variable vom Typ
va_list wird die Liste der unbekannten Parameter
verwaltet. Sie muss natürlich vor dem Zugriff auf diese deklariert sein.
va_start()
Dieses Makro wird mit der Variablen vom Typ
va_list und dem letzten
namentlich deklarierten Parameter aufgerufen.
Es setzt den Zeiger in der Liste auf den ersten Parameter der mit den drei Punkten umschriebenen
Liste.
va_arg()
Jeder Aufruf von
va_arg() gibt einen Wert des angegebenen Typs zurück
und schiebt dann der Zeiger in der Liste zum nächsten Parameter.
Der Programmierer ist selbst verantwortlich dafür, daß nicht mehr Parameter aus der Liste
abgeholt werden, als sich darin befinden, und daß der Typ des Parameters in der Liste mit dem
Typ der Zielvariable übereinstimmt.
va_end()
Dieses letzte Makro gibt die Parameter-Liste wieder frei. Die Variable ist anschließend
undefiniert.
Hinweise
Zwei Hinweise zu dieser kurzen Beschreibung des Themas will ich hier noch geben :
-
Die Abfolge der Aufrufe va_start() ... va_arg() ... va_arg() ...
va_end() kann beliebig oft wiederholt werden. So ist es möglich die Liste der
Parameter nicht nur einmal zu durchlaufen.
-
Es ist sehr zu empfehlen, sich die Manpage zu den genannten Funktionen sorgfältig
durchzulesen, z.B. im Webbrowser nach "man va_start" suchen (für Linux z.B. gibt es eine
hier).
Sie beschreibt die Möglichkeiten und Fallstricke dieser Funktionalität wesentlich
besser und ausführicher als mein kurzer Überblick.
© Uwe Jantzen 13.12.23