C für PICs: Funktionen
zurück zu
C für PICs , C-Compiler , PIC-Prozessoren , Elektronik , Homepage
C für PICs
Grundlagen von C
Variablen
Funktionen
Operationen
Programmablaufsteuerung
Arrays und Strings
Pointer
Strukturierte Typen
PIC-spezifisches
zurück zu C für PICs
Funktionen
Der ausführbare Programmcode jedes C-Programms besteht aus
Programmblöcken, die Funktionen genannt werden. So eine Funktion
kann man aufrufen, dann wird der Code in dieser Funktion vom
Prozessor abgearbeitet, und danach kehrt der Prozessor zum rufenden
Programm zurück. Funktionen können wieder andere Funktionen
aufrufen. Eigentlich könnte man auch den gesamten Code in einen
einzigen Block (die main-Funktion
eines C-Programms) schreiben,
main()
{
anweisung1;
anweisung2;
anweisung3;
anweisung4;
anweisung5;
}
aber es gibt oft Programmschnipsel, die man an mehreren Stellen des
Programms immer wieder benötigt. Im folgenden Beispiel ist das
die drei mal auftretende Gruppe von anweisung1 bis anweisung5.
main()
{
anweisung1;
anweisung2;
anweisung3;
anweisung4;
anweisung5;
_was_anderes;
anweisung1;
anweisung2;
anweisung3;
anweisung4;
anweisung5;
_noch_was_anderes;
anweisung1;
anweisung2;
anweisung3;
anweisung4;
anweisung5;
_ganz_was_anderes;
}
Anstatt diesen Code nun an jeder "bedürftigen" Stelle im
Hauptprogramm einzufügen, schreibt man ihn nur ein mal in eine
Funktion, und ruft dann diese eine Funktion an diesen Stellen
jeweils auf. Das Programm wird dadurch kleiner, übersichtlicher und
leichter zu pflegen.
anweisung1bis5()
{
anweisung1;
anweisung2;
anweisung3;
anweisung4;
anweisung5;
}
main()
{
anweisung1bis5();
_was_anderes;
anweisung1bis5();
_noch_was_anderes;
anweisung1bis5();
_ganz_was_anderes;
}
Definition und Prototypen
Jedes C-Programm enthält einen Haupt-Funktion mit dem Namen main. Beim Start des PICs
(power-on oder reset) wird diese Funktion aufgerufen. Im PIC sollte
die Funktion main nie zu
ende gehen (Endlosschleife), passiert es doch, dann wird ein Reset
ausgelöst. Alle anderen Funktionen bekommen vom Programmierer einen
Namen zugeteilt.
Im Folgenden sehen wir ein kleines C-Programm, das aus einer main-Funktion sowie einer
zusätzliche Funktion mit dem Namen fu1
besteht. Die main-Funktion
ruft die Funktion fu1 auf.
Diese Funktion macht hier allerdings nichts, außer nach ihrer
Beendigung (return) wieder
zu main zurückzukehren.
Wie wir sehen, endet damit auch main.
In einem Personalcomputer wäre damit das Programm beendet, und das
Betriebssystem übernimmt wieder die Kontrolle. Im PIC gibt es kein
Betriebssystem, und es würde ein Reset erfolgen. Das ist hier noch
ein Mangel, den ich später beheben werde.
fu1()
{
return;
}
main()
{
fu1();
}
Im Folgenden vertausche ich die beiden Funktionen des Programms.
main()
{
fu1();
}
fu1()
{
return;
}
Eigentlich
scheint
sich
nichts geändert zu haben. Trotzdem enthält das Programm nun einen
Fehler, auf den der Compiler stoßen wird. Der Compiler arbeitet des
Quelltext von oben nach unten ab. Dabei stößt er innerhalb der main-Funktion
auf den Aufruf der Funktion fu1.
Diese kennt er aber noch nicht (während main immer bekannt ist). Weshalb er das Compilieren
mit einem Fehler abbrechen wird. Funktionen sollten also immer
definiert sein, bevor sie
aufgerufen werden.
Um dieses Problem zu entschärfen, gibt es Funktions-Prototypen. Das
sind vorgezogene Kurzbeschreibungen der Funktionen, die eigentlich
nur aus dem Funktionskopf bestehen. Sie stehen am Programmanfang,
wenigstens aber vor dem ersten Aufruf der Funktion. Der Compiler
kennt dann beim ersten Aufruf der Funktion wenigstens ihren Namen
(und die Funktions-Parameter), was ausreichend ist. Es muss dann
aber im späteren Programmverlauf zwingend noch die vollständige
Funktionsdefinition enthalten sein, oder es wird wieder ein Fehler
gemeldet.
fu1();
main()
{
fu1();
}
fu1()
{
return;
}
Etwas habe ich bisher weggelassen. Nun werde ich es ergänzen. An
Funktionen kann man Argumente übergeben, und eine Funktion kann auch
ein Argument zurückgeben. Beides wird gleich erläutert. Wird auf
solche Übergaben verzichtet (wie in unserem Beispiel), dann muss
jeweils der Platzhalter void an
Stelle der Argumente eingetragen werden. Das Listing sieht dann so
aus:
void fu1(void);
void main(void)
{
fu1();
}
void fu1(void)
{
return;
}
Argumentübergabe
Innerhalb einer Funktionen werden normalerweise Daten verarbeitet.
Diese Daten stehen natürlich in Variablen.
Geeignet wären dafür globale Variablen, auf die von überall, also
auch aus Funktionen heraus, zugegriffen werden kann.
Wesentlich flexibler können Funktionen aber genutzt werden, wenn
ihnen beim Aufruf ein Wert direkt übergeben werden kann. Genau dazu
dienen die runden Klammern hinter dem Funktionsnamen. Hier hinein
schreibt man beim Funktionsaufruf den zu übergebenden Wert. Das kann
z.B. eine Zahl sein, oder eine Variable, oder irgendein anderer
Ausdruck, der einen Wert ergibt. Damit das klappt, muss der Compiler
aber wissen, welchen Typ dieser Wert hat. Diese Festlegung erfolgt
im Kopf der Funktionsdeklaration, wo auch schon der Funktionsname
festgelegt wurde. Im nachfolgenden Beispiel wird die Funktion so
definiert, dass man ihr eine integer-Zahl beim Aufruf übergeben
muss. Beim Aufruf der Funktion wird dann automatisch eine lokale int Variable mit dem
übergebenen Wert angelegt. In unserem Fall ist das die lokale
Variable a.
void fu1(int a)
{
return;
}
Die Funktion fu1 macht zwar noch gar nichts, aber ein Programm mit
dieser Funktion könnte so aussehen:
void fu1(int a);
void
main(void)
{
int b;
b = 8;
fu1(5);
fu1(b);
fu1(3+b);
}
void fu1(int a)
{
return;
}
Im oben stehenden Beispiel wird die Funktion fu1 drei mal
aufgerufen. Jedes mal wird ihr ein integer-Wert als Parameter
übergeben, um verschiedene Varianten zu demonstrieren. Man beachte,
dass am Programmanfang wieder ein Funktionsprototyp der Funktion fu1
steht, der ebenfalls die Definition der zu übergebenen Parameter
enthält.
Man kann einer Funktion auch mehrere Parameter gleichen oder
unterschiedlichen Typs übergeben:
void fu1(int a, int b, float c);
void
main(void)
{
fu1(5,
77,
22.5);
}
void fu1(int a, int b,
float c)
{
return;
}
Man beachte, dass die Parameterübergabe eine Daten-Einbahnstraße in
die Funktion hinein darstellt. Eine Rückübergabe veränderter Werte
aus der Funktion heraus ist damit nicht möglich.
Argumentrückgabe
Aber wie kann eine Funktion ein Ergebnis der Datenverarbeitung an
den Rest des Programms zurückgeben? Zum einen gibt es da natürlich
globale Variablen, die auch innerhalb einer Funktion mit Werten
beschrieben werden können.
Deutlich flexibler ist aber die Argumentrückgabe. Jede gerufene
Funktion kann genau einen
Wert eines Typs an
die aufrufende Funktion zurückgeben. Dafür betrachtet man einfach
die Funktion als Ausdruck eines bestimmten Typs. Der Typ der
Funktion muss natürlich in der Funktionsdeklaration (und auch im
Prototypen) festgelegt werden. Der Typbezeicher wird dazu in der
Deklaration dem Funktionsnamen vorangestellt. In diesem Beispiel ist
es int.
int fu1(int a)
{
return(5);
}
Die Funktion kann jetzt einen integer-Wert an die rufende Funktion
zurückgeben. Das geschieht durch den return-Befehl. Dieser Befehl beendet die
Funktionsabarbeitung. Der Wert des in der runden Klammer hinter return stehenden Ausdrucks wird
zurückgegeben. Er muss natürlich den richtigen Typ (hier also int) haben. Die oben definierte
Funktion wird also immer "5" liefern, was noch ein wenig primitiv
ist.
Ich habe gerade eine tolle Idee. Man kann den numerischen Wert
zweier Ausdrücke zusammenfassen!! Ich nenne das "die Addition" und
werde es als Softwarepatent
anmelden. Zunächst werde ich aber eine Funktion schreiben, die
die Summe zweier int-Werte
bildet. Diese Funktion nenne ich passender Weise "summe".
int summe(int a, int b);
void
main(void)
{
int c;
c
= summe(5, 77);
}
int summe(int a, int b)
{
return(a+b);
}
Man sieht, dass an die summe-Funktion
zwei int-Argumente
übergeben werden müssen. Innerhalb der Funktion stehen diese Werte
dann in den lokalen Variablen a
und b. Der Typ des
Rückgabearguments (also der Typ der Funktion) ist ebenfalls int. Innerhalb der Funktion
steht ein return-Befehl,
der die Summe von a und b zurückgibt.
In main wird summe mit den
integer-Argumenten 5 und 77 aufgerufen. Anstelle dieser Zahlen
könnte man auch integer-Variablen einsetzen. Die summe-Funktion
gibt
die Summe von 5 und 77 an die rufende main-Funktion
zurück. Dort wird das Ergebnis in der integer-Variablen c abgespeichert.
-->
weiter
zu
Operationen
zurück
zu C für PICs , C-Compiler , PIC-Prozessoren , Elektronik , Homepage
Autor: sprut
erstellt: 01.10.2007
letzte Änderung: 26.04.2015