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 iherer 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 irgentein 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 obenstehenden Beispiel wird die Funktion fu1 drei mal aufgerufen.
Jedesmal 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 Prototyen)
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: 01.10.2007