Also, angeommen, du hast sowas hier:
|
C-/C++-Quelltext
|
1
2
3
4
5
6
7
8
|
int Funktion(int a, int b)
{
return a+b;
}
...
int Ergebnis=Funktion(5, 18-4);
|
Was semantisch passiert, ist ungefähr folgendes:
- Die Ausdrücke in den Parametern werden ausgewertet. Bei der 5 ist man schon fertig, bei dem 18-4 führt man erst die Rechnung durch, taucht eine Variable auf, wird deren Inhalt geladen.
- Nachdem alle Werte feststehen, werden sie in den Parameterspeicher für die Funktion kopiert.
- Die Funktion kann auf diesen Speicher zugreifen und mit den Werten tun, was sie will.
- Die Funktion errechnet ein Ergebnis. Die Return-Anweisung kopiert das Ergebnis in einen Ergebnis-Speicherplatz.
- Alle Speicherbereiche die die Funktion verwendet hat, werden freigegeben - mit Ausnahme des Ergebnis-Speicherplatzes.
- Der Funktionsaufruf ist beendet und der Aufrufer der Funktion kann auf den Ergebnis-Speicherplatz zugreifen.
Wenn man das genau so machen würde, würde man oft Werte hin und her kopieren, was unnötig langsam ist. Deshalb kann der Compiler optimierten Code generieren, was einfach bedeutet, dass der Code etwas anderes tut, aber immer das selbe Ergebnis dabei produziert. Es gibt dabei noch ein paar Regeln, was auf jeden Fall immer passieren muss, aber trotzdem hat der Compiler noch viele Freiheiten. Es ist zum Beispiel möglich, dass das Objekt, was am Ende zurückgegeben wird, überhaupt nicht im Speicher der Funktion erstellt wird, sondern direkt im Speicher des Aufrufes, so dass beim zurückkehren überhaupt nichts kopiert oder verschoben werden muss. Man will natürlich ein wenig darauf achten, dass man den Code so schreibt, dass der Compiler gute Möglichkeiten zum optimieren findet, aber im Grunde genommen, muss man sich keine Gedanken darüber machen, wie der Code genau funktioniert, so lange man weiß, welche Auswirkungen er genau hat.