Programmieren
 
 
 
 
 
C-Grundkurs
 
 
 
 
 
.. funktionen()
 
 

 
 
 
 
 
Das Unterprogramm
Wie bei jeder anderen Programmiersprache wird das was man 'das Programm' nennt, in der Regel aus einer Vielzahl von Teilprogrammen gebildet. Diese Teilprogramme nennt man im allgemeinen 'Unterprogramme'. Unterprogramme werden immer an einer Stelle des übergeordneten Programmteils aufgerufen, dann durchlaufen und kehren nach dem Durchlauf zu dem übergeordneten Programmteil zurück. Die Programmausführung setzt sich nun hier, mit der Ausführung weiterer Befehle und Unterprogrammaufrufen fort.
 
 
 
 
Das Bild möchte diese Struktur verdeutlichen. Aus einer Programmschleife des Betriebssystems heraus, wird das Programm eines Anwenders aufgerufen. Für das Betriebssystem ist dieses Programm ein Unterprogramm, das nach seiner Beendigung zum nächsten Befehl der Auswahlschleife im Betriebssystem zurückkehrt.
Aber auch das Anwenderprogramm kann seinerseits Unterprogramme benutzen. Dabei besteht deren Vorzug darin, dass ein bestimmtes Verfahren nur einmal programmiert werden muss, dann aber beliebig oft durch einen Sprung zum Unterprogramm abgerufen werden kann. Das macht Programme kürzer, als wenn sie linear programmiert würden.
 
 
 
 
 
Die Unterprogramme in C .. funktionen();
Die Unterprogramme der Hochsprache C nennen werden Funktionen genannt. Diesen Namen tragen sie in Anlehnung an Funktionen der Mathematik, die aus vielen Variablen und Konstanten immer nur einen Wert errechnen können. Bei C-Funktionen ist das ähnlich, auch sie können in ihrer Grundfunktion nur einen Wert zurückgeben, jedoch beliebig viele Übergabeparameter erhalten.

In C ist der erste übergeordnete Programmteil ein Assembler-Startprogramm, das dem Benutzer im normalen Umgang nicht zugänglich ist. Dieses ruft die Hauptfunktion des Benutzers auf, die deswegen unbedingt den Namen main() tragen muss. Von main() aus kann der Benutzer beliebige weitere Funktionen aufrufen, die er selber geschrieben hat, oder die aus der, zusammen mit der IDE ausgelieferten, statischen Bibliothek stammen.

Bei der Arbeit mit Funktionen sind 3 Arbeitsschritte zu beachten ..
 
 

 
 
1. Die Definition
Unter der Definition einer Funktion versteht man deren Programmierung, oder besser die Anfertigung ihres Quelltextes, nach bestimmten Regeln.


  • Bei Funktionen der statischen Bibliothek ist dieser Vorgang bereits abgeschlossen und das fertige Maschinenprogramm befindet sich in einer Bibliothek, der Library, (Endung .lib) die normalerweise vom Hersteller der C-Entwicklungsumgebung mitgeliefert wird. Man kann eine solche Bibliothek über mitgelieferte Hilfsprogramme ,Tools, auch selber aufbauen.
  • Bei eigenen Funktionen muss der Quellcode nach Syntaxregeln, die weiter unten erklärt sind, geschrieben werden. Dann wird die Funktion compiliert und liegt nun auch als relokatibles Maschinenprogramm.obj vor, so wie die Funktionen der Bibliothek.
 
 

 
 
2. Die Deklaration
Die Deklaration ist ein Sicherheitsmechanismus zur Fehlererkennung, der von dem Compiler ausgenutzt wird um Fehlermeldungen erzeugen zu können. Bei der Deklaration wird dem Compiler erklärt, deklariert, dass es eine Funktion mit dem angegebenen Namen gibt und welche Eigenschaften diese in Bezug auf die Übergabe und Rückgabe von Variablen besitzt. Dieser Kontrollmechanismus ist unverzichtbar, auch wenn es unter bestimmten Umständen gelingt ein Programm ohne Deklaration zum Laufen zu bringen. Die Deklaration besteht aus einer Zeile, die dem Kopf der Funktion gleicht, aber mit einem Semikolon ';' abgeschlossen ist. Man findet diese Zeile ...


  • Bei Funktionen der statischen Bibliothek in Dateien, die sich Kopf- oder Headerdateien, nennen. Sie wurden zusammen mit der statischen Bibliothek ausgeliefert. Die benötigten Headerdateien.h, für Funktionen aus der statischen Bibliothek, müssen über den Präprozessorbefehl #include <Name der Headerdatei> in das eigene Programm eingefügt werden. Dass in den Headerdateien mehr Funktionsköpfe deklariert werden, als man eigentlich benutzt, stört dabei nicht. Nur wenn man es vergisst zu einer Bibliotheksfunktion die Datei mit den Funktionsköpfen einzubinden, gibt es eine Fehlermeldung des Compilers.
  • Bei eigenen Funktionen muss die Kopf- oder Headerzeile selber angefertigt werden und am Anfang des eigenen Quelltextes, in jedem Fall vor dem ersten Aufruf der deklarierten Funktion, stehen.
  • Bei der Hauptfunktion main() ist keine Kopfzeile notwendig. Sie ist dem Compiler in ihrem gesamten Grundaufbau bekannt.
 
 

 
 
3. Der Aufruf
Nachdem eine Funktion angefertigt wurde, also durch Definition und Deklaration vorbereitet ist, kann man sie benutzen. Der Aufruf einer Funktion gleicht dem Start des Unterprogramms. Man kann eine Funktion nur starten, wenn man ihren Namen kennt und weiß, welche Parameter (Konstante, Zahlen, Variable oder Ausdrücke) übergeben werden müssen. Zudem sollte man wissen was die Funktion dann tut und ob sie auch einen Wert zurückliefert. Diese Informationen erhält man ..


  • bei den Funktionen der statischen Bibliothek aus dem mitgelieferten Handbuch oder der OnlineHilfe [Strg] [F1]. Hier wird auch gesagt, welche Headerdatei.h zur Benutzung der Funktion mit #include eingebunden werden muss.
  • bei den eigenen Funktionen sollte man es wissen, wozu sie taugen und welche Parameter übergeben werden müssen .. oder es sich notiert haben. Hierzu können Kommentare und die Kopfzeile behilflich sein.
 
 

 
 
 
 
 
Deklarations- und Definitions-Syntax von C -Funktionen
Die Deklarationszeile oder die Definition einer Funktion muss vor ihrem ersten Aufruf platziert sein.
Da es bei umfangreicheren Programmen mit viel Aufwand verbunden ist die Definitionen immer vor ihrem ersten Aufruf im Quelltext anzuordnen, Deklarationen dagegen in Headerdateien zusammengefasst werden können, ist es sinnvoll am Anfang eines Quelltextes mit den Deklarationen der verwendeten Funktionen zu beginnen.

Die Minimalsyntax lautet ..
 
 
Variablentyp FunktionsName(Variablentyp,Variablentyp,usw.);
 
 
Die Deklaration besteht im Wesentlichen aus dem Funktionskopf einer Funktion, der mit einem Semikolon abgeschlossen ist. Dabei können die Variablennamen weggelassen werden. Besser ist es aussagekräftige Variablennamen einzufügen, so dass aus ihnen hervorgeht, welchem Zweck die Übergabe dient.

Deklarationen stehen immer ganz vorne im Programm, während die Definition der Funktion und ihr Aufruf an einer beliebigen Stelle des Quelltextes folgen kann. Sollen einer Funktion keine Parameter übergeben werden, so wird anstelle eines Variablentyps der Typ als void (leer) gekennzeichnet.

Beispiel:
 
int FunktionsName (void);    // Deklaration

// beliebiger anderer Quelltext mit Funktionsaufrufen oder
// Funktionsdefinitionen ..


int FunktionsName (void)     // Funktionskopf
{
  Befehle der Funktion       // Funktionskörper zwischen {}
  return(5);
}
 
 
 
 
Der Funktionskopf baut sich wie folgt auf...
 
 
  • die Typangabe des Rückgabewertes. Dieser kann bei der Rückkehr der Funktion, einer Variablen des gleichen Typs übergeben werden. Im Beispiel int. Das bedeutet, dass eine Zahl im Bereich zwischen –32.768 und +32.767 zurückgegeben werden kann. void hätte hier bedeutet, dass kein Rückgabewert vorgesehen ist.
 
 
  • der Name der Funktion, Achtung .. Groß- und Kleinschreibung wird unterschieden.
 
 
  • zwischen runden Klammern ( ) und durch Kommata getrennt, werden die Übergabeparameter an die Funktion angegeben. void bedeutet, dass keine Parameter zur Arbeit der Funktion benötigt werden.
 
 
 
 
 
Der Funktionskörper baut sich wie folgt auf..
 
 
{
 
 
  • zwischen zwei geschweiften Klammern { .. } stehen die Befehle, die das Unterprogramm ausmachen ... wird die zweite Klammer erreicht, ist das Programm beendet und kehrt zum übergeordneten Programmteil zurück. Die Befehle des Funktionskörpers müssen durch ein Semikolon getrennt werden.
 
 
   return (eine Rückgabevariable oder Konstante);
 
 
  • Dieser Befehl ist nur notwendig, wenn die Funktion etwas zurückgeben soll. Im Beispiel soll sie es und gibt die Integerkonstante 5 zurück. Es kann hier auch eine Variable stehen, deren Inhalt nach einer Rechnung zurückgegeben wird. Wenn die Rückgabe der Funktion void ist, kann return entfallen. (Da das Schlüsselwort return keine Funktion darstellt, kann sowohl   return 5;  , als auch   return(5);   geschrieben werden.
 
 
}
 
 
 
 
 
Obige Funktion könnte in einem übergeordneten Programm aufgerufen werden die Syntax hierzu würde dann lauten ..
 
 
void main(void)
{
 int a;
 a = funktion();
}
 
 
Nach diesem Aufruf wäre die Variable a vom Typ Integer mit dem Wert 5 gefüllt.
 
 

 
 
 
 
 
Mehr zu Funktionen
Funktionen sind das einzige Programmkonstrukt der Sprache C. Bereits das 'Haupt'Programm main() ist eine Funktion, die von dem Betriebssystem aufgerufen wird. Funktionen stellen eine besondere Art von Unterprogrammen dar.
 
 
 
 
 
  • .. sie können eine beliebige Anzahl Übergabe-Parameter besitzen, die durch Kommata getrennt sind und hinter dem Namen der Funktion zwischen runden Klammern stehen. Die Parameter werden als Zahlen über den Stack an die Funktion weitergegeben, nicht durch ihren Namen.
  • .. sie können maximal einen Wert zurückgeben. Dieser Rückgabewert kann vom aufrufenden Programm benutzt werden, muss es jedoch nicht. Er wird über die Prozessorregister der CPU zurückgegeben. Wird ein Rückgabeparameter nicht in eine eigene Variable übertragen, so geht er bei den nächsten Aktionen des Prozessors verloren.
  • .. sie dürfen nicht verschachtelt werden, stehen also immer außerhalb jeder anderen Funktion (Sie besitzen eine globale Gültigkeit). Das bedeutet nicht, dass eine Funktion keine weitere Funktion aufrufen darf. Sie darf nur nicht innerhalb einer zweiten Funktion definiert werden.
Die Abfolge in der Funktionen in einem Gesamtprogramm definiert werden ist beliebig, solange Deklarationen vorhanden sind. Ein Funktionsaufruf kann stattfinden bevor die Funktion definiert wurde, wenn zuvor eine Deklaration stattfand.
Das gilt auch für die Funktion main(). Sie kann irgendwo im Programmtext stehen. Der Grund hierfür ist die Tätigkeit des Linkers. Er sammelt zunächst alle Aufrufstellen von Funktionen in einer Liste, und bindet gleichzeitig alle Funktionen zu einem Programmblock zusammen. Nun kennt er die tatsächlichen Laufstellen der Teilprogramme und setzt die Adressen nachträglich an den Aufrufstellen ein. Aus diesem Grund müssen Funktionen aber deklariert sein, denn der Compiler soll ja prüfen ob eine Funktion richtig angewendet wurde und das kann er nur, wenn er die Anzahl der übergebenen Parameter und ihren Typ kennt. *)

Wie oben geschildert werden Funktionen in zwei Schritten aufgebaut. Zunächst werden sie wie Variable deklariert (dem Compiler in ihrem Aufbau erklärt), dann definiert (als hardwaremässiges Datenobjekt angelegt).

Deklaration einer C- Funktion:
 
 
typ Rückgabeparameter funktions_name (typ Parameter1, typ Parameter2, ..) ;
 
 
Durch die Deklarationszeile kennt der Compiler den typ des Rückgabeparameters und der Übergabeparameter sowie deren Anzahl. Diese Kenntnis genügt ihm, um spätere Aufrufe der Funktion auf ihre Richtigkeit hin zu überprüfen. Die Angabe der Parameternamen kann optional (wahlweise) hinzugefügt werden. Sie sind nur für den Benutzer der Funktion interessant. Aus ihnen kann er erkennen, welche Bedeutung die übergebenen Parameter besitzen.
Die Deklarationen von benutzten Funktionen muss in einem Programm ganz am Anfang erfolgen. Man kann natürlich alle Deklarationen in einer Kopfdatei (Headerdatei auch IncludeDatei genannt) zusammenfassen und mit dem Befehl #include“mein Verzeichnispfad“ im Programm einbinden.

Der Typ 'void' vor einer Funktion oder zwischen den Klammern bedeutet, dass eine Funktion entweder keinen Wert zurückgibt, oder keine Übergabeparameter benötigt.

Definition einer C- Funktion:
 
 
typ Rückgabeparameter funktions_name (typ Parameter1, typ_Parameter2, ..)
{
     // Befehlsblock der die übergebenen Parameter ausnutzt
    return (Rückgabeparameter);
}
 
 
Die Definition einer Funktion enthält das eigentliche Programm. Sie besteht aus der Kopfzeile der Funktion, dem Header, sowie dem Funktionskörper, dem Body. Dieser muss zwischen zwei geschweiften Klammern stehen.
Die Typ-Angaben der Variablen im Header müssen mit denen der Deklaration übereinstimmen, ebenso deren Anzahl. Die Namen der Parameter nicht. Die Namen der angegebenen Parameter sollten kurz sein, denn sie sind als Variablennamen innerhalb des Befehlsblocks verwendbar. Neben diesen übergebenen Variablen können weitere Variable zu Beginn des Befehlsblocks erklärt werden. Soll eine Funktion einen Rückgabewert besitzen, so muss dieser in einer 'return()' -Anweisung genannt werden. Gibt die Funktion keinen Wert zurück entfällt die 'return'-Anweisung aber ihr Rückgabetyp wäre in diesem Fall auch void..

Die Anweisung return kann dennoch ohne Rückgabevariable irgendwo in einer Funktion auftreten um diese vorzeitig zu beenden.

Nachdem eine Funktion fertiggestellt, also definiert wurde, kann man sie ...
  • als Quelltext zusammen mit Deklarationen und anderen Funktionen in einer Kopfdatei aufbewahren und mit #include“Pfadangabe“ in das Hauptprogramm einbinden oder ..
  • nur compilieren und als Objektdatei.obj durch den Linker in das Hauptprogramm einbinden lassen oder..
  • als Objektdatei in eine eigene Bibliothek übertragen, von wo aus sie ebenfalls durch den Linker geholt und eingebunden wird.

Aufruf einer C- Funktion:
 
 
a = funktions_name (Parameter1, Parameter2, ..);
 
 
Funktionen können aus dem Befehlsblock einer jeden anderen Funktion heraus aufgerufen werden. Ruft sich eine Funktion selber auf, dann nennt man sie rekursiv. Diese Technik sollte aber zunächst auf 'später' verschoben werden.
Der Rückgabewert einer Funktion kann in einer Variablen des aufrufenden Programms gespeichert werden. Will man den Rückgabewert nicht haben, unterbleibt die Zuweisung ' a ='.

Die Namen der beim Aufruf einer Funktion angegebenen Rückgabe- und Übergabeparameter müssen nicht denen in der Definition entsprechen, allerdings müssen sie dem dort angegeben Typ entsprechen. Ebenso muss ihre Anzahl mit der in der Definition genannten übereinstimmen. (Ausnahme Ellipsen)
Die übergebenen Parameter können konstante Zahlen, Variablen oder noch zu berechnende mathematische Ausdrücke darstellen. In allen Fällen werden die angegebenen Parameter als Zahlen auf dem Stack (einem Speicherbereich im RAM) abgelegt und von der aufgerufenen Funktion dort abgeholt. Die Variablen im aufrufenden Programms bleiben dadurch unverändert erhalten, auch wenn es den Anschein hat, als würde die Funktion mit ihnen Berechnungen anstellen. Die Funktion rechnet nur mit den Kopien vom Stack. (s.a. Gültigkeitsbereich, Sichbarkeit, Dauer bei C-Objekten)
 
 
------------------------------
 
 
*) Wird eine Funktion vor ihrem ersten Aufruf definiert, so kann die Deklaration entfallen. Das ist aber bei grösseren, unübersichtlich gewordenen Programmen gefährlich und deswegen ein schlechter Programmierstiel.
 
 
 
 
www..de