Wann darf man was aus einer Funktion nicht returnen?
-
int f1(int i) { int a = 5; int b = a - i; return b; } int main() { int c = 7; int d = f1(c); return d + 2; }
daraus wird ohne Optimierungen:
.text:00400496 <f1>: .text:00400496 55 push %rbp .text:00400497 48 89 e5 mov %rsp,%rbp .text:0040049a 89 7d ec mov %edi,-0x14(%rbp) .text:0040049d c7 45 fc 05 00 00 00 movl $0x5,-0x4(%rbp) .text:004004a4 8b 45 fc mov -0x4(%rbp),%eax .text:004004a7 2b 45 ec sub -0x14(%rbp),%eax .text:004004aa 89 45 f8 mov %eax,-0x8(%rbp) .text:004004ad 8b 45 f8 mov -0x8(%rbp),%eax .text:004004b0 5d pop %rbp .text:004004b1 c3 retq .text:004004b2 <main>: .text:004004b2 55 push %rbp .text:004004b3 48 89 e5 mov %rsp,%rbp .text:004004b6 48 83 ec 10 sub $0x10,%rsp .text:004004ba c7 45 fc 07 00 00 00 movl $0x7,-0x4(%rbp) .text:004004c1 8b 45 fc mov -0x4(%rbp),%eax .text:004004c4 89 c7 mov %eax,%edi .text:004004c6 e8 cb ff ff ff callq 0x00400496 <f1> .text:004004cb 89 45 f8 mov %eax,-0x8(%rbp) .text:004004ce 8b 45 f8 mov -0x8(%rbp),%eax .text:004004d1 83 c0 02 add $0x2,%eax .text:004004d4 c9 leaveq .text:004004d5 c3 retq .text:004004d6 66 2e 0f 1f 84 00 00 00 00 00 nopw %cs:0x0(%rax,%rax,1)
An welcher Stelle wird ein Parameter oder ein Rückgabewert also NICHT kopiert?
Und ich kann ja nix dafür, wenn dieses behavior, call by value result(bzw. return) heißt.
-
@EinNutzer0 sagte in Wann darf man was aus einer Funktion nicht returnen?:
Und ich kann ja nix dafür, wenn dieses behavior, call by value result(bzw. return) heißt.
Heißt es nicht.
@EinNutzer0 sagte in Wann darf man was aus einer Funktion nicht returnen?:
An welcher Stelle wird ein Parameter oder ein Rückgabewert also NICHT kopiert?
Deine ganzen Überlegungen sind ziemlich sinnlos.
§5.1.2.3 Program execution
- The semantic descriptions in this document describe the behavior of an abstract machine in which issues of optimization are irrelevant.
Das heißt salopp gesagt: "Es muss nur dasselbe beobachtbare Verhalten dabei rauskommen. Wie ist völlig egal."
Du bist hier im C-Forum. Hier geht es um die Sprache. Wenn Du über das Verhalten einer bestimmten Implementierung reden willst dann geh' ins Compiler- und IDE-Forum.@EinNutzer0 sagte in Wann darf man was aus einer Funktion nicht returnen?:
int f1(int i) { int a = 5; int b = a - i; return b; } int main() { int c = 7; int d = f1(c); return d + 2; }
int main() { return 0; }
immer noch dasselbe. Da kannst noch so viele Verrenkungen machen (Scherze wie
volatile
, funktionen mit external linkage (wobei ... Interprocedural optimization) und user input mal ausgenommen.). Einen Compiler der das bei geringsten Optimierungen nicht schnallt kannst getrost in die Tonne treten.main: mov eax, 0 ret
Wie Du siehst gibt es hier nichtmal einen Funktionsaufruf. Vielleicht verstehst Du jetzt ja endlich "as-if".
-
@Swordfish sagte in Wann darf man was aus einer Funktion nicht returnen?:
@EinNutzer0 sagte in Wann darf man was aus einer Funktion nicht returnen?:
Und ich kann ja nix dafür, wenn dieses behavior, call by value result(bzw. return) heißt.
Heißt es nicht.
Bevor Du nochmal damit kommst:
https://condor.depaul.edu/ichu/csc447/notes/wk4/ps.html
Call by value-result
A call by value-result, like a call by reference, requires that the argument be a variable. However, the parameters of the function or procedure are not directly bound to the variable's address. Rather, they get their own space within their own scope, and when the function or procedure is terminated, the new values of the parameters are copied back into the caller's variables. Hence, value-result differs from reference only in that the values of the caller's variables are not modified while the function or procedure is still in effect--only when it has finished.
One advantage of calling by value-result is that the called procedure or function can safely assign to its parameters without fear of confusing side effects. (This, for example, is not true with a call by reference or by name.) On the other hand, making life easier for the callee makes life more confusing for the caller. Consider the following code:
proc a (int x, int y) { x = 1; y = 2; } int t; a (t,t); print t;
The value of
t
after calling a then depends on the order of parameter copies when the procedure call is finished.Soetwas gibt es weder in C noch in C++.
-
#include <stdio.h> typedef struct test_e { int i; char *cp; } Test_E; int main() { Test_E a = {5, "hallo"}; Test_E b = a; printf("%d %s, %d %d %d\n", b.i, b.cp, &a == &b, &a.i == &b.i, &a.cp == &b.cp); printf("%p %p %p %p %p %p\n", (void *)&a, (void *)&b, (void *)&a.i, (void *)&b.i, (void *)&a.cp, (void *)&b.cp); return 0; }
$ ./TestC2.out 5 hallo, 0 0 0 0x7ffd9baaa950 0x7ffd9baaa940 0x7ffd9baaa950 0x7ffd9baaa940 0x7ffd9baaa958 0x7ffd9baaa948
Hier erschließt sich mir Zeile 12 bis 14 und die Ausgabe überhaupt nicht... Jeder Vergleich ist falsch, und ich hätte angenommen, dass erster und dritter Vergleich
true
sind... Kopiert das=
den kompletten Speicherbereich inkl.. Pointer einer Struktur? Würde selbiges dann auch bei einemreturn
geschehen? Sorry, wenn sich diese Fragen für euch furchtbar anhören, aber ich möchte C (und C++) verstehen.
-
Warum sollten bei dem Vergleich die Adressen von
a
undb
denn gleich sein (in der 3. Zeile der Ausgabe stehen diese doch)?
Wolltest du die Inhalte vergleichen, alsoprintf("%d %s, %d %d %d\n", b.i, b.cp, !memcmp(&a, &b, sizeof(Test_E)), a.i == b.i, a.cp == b.cp);
?
PS: memcmp gibt bei "gleich"
0
zurück (daher die Negation mittels!
)PPS: Bedenke auch, daß
memcmp
alle Bytes vergleicht (also auch evtl. Padding-Bytes, welche dann nicht unbedingt gleich sein müssen).
-
Also, ich habe die Ausgabe nicht manipuliert. Ich bin auch davon ausgegangen, dass
&a == &b
NICHT 0 liefert (zumal eine Zeile darunter unterschiedliche Adressen stehen) - aber das Gegenteil ist der Fall. Was hab ich falsch gemacht? Oder will mich der Compiler ärgern?Bitte beantwortet mir noch diese Frage: Was geschieht bei
return a;
?
-
@EinNutzer0 sagte in Wann darf man was aus einer Funktion nicht returnen?:
Also, ich habe die Ausgabe nicht manipuliert. Ich bin auch davon ausgegangen, dass
&a == &b
NICHT 0 liefert (zumal eine Zeile darunter unterschiedliche Adressen stehen) - aber das Gegenteil ist der Fall. Was hab ich falsch gemacht?Was wird denn bei
&a == &b
verglichen?
-
@john-0 sagte in Wann darf man was aus einer Funktion nicht returnen?:
Was wird denn bei
&a == &b
verglichen?Wenn ich das wüsste, dann würde ich hier nicht fragen...
Edit: Wird der string "hallo" auch kopiert?
-
@EinNutzer0 sagte in Wann darf man was aus einer Funktion nicht returnen?:
Wenn ich das wüsste, dann würde ich hier nicht fragen...
Dir ist die Bedeutung des Operators
&
bewusst? Der liefert die Adresse einer Variablen zurück! D.h. bei&a == &b
werden die Adressen der beiden Variablen verglichen und eben nicht deren Werte. Die beiden Variablen a und b liegen natürlich an unterschiedlichen Stellen auf dem Stack. D.h. solange Du hier die Speicherstellen miteinander vergleichst ist das natürlich zu erwarten, dass da Ungleichheit festgestellt wird. In C gibt es keine Möglichkeit den Operator==
fürstruct
zu überladen, d.h.a == b
kann hier bei Dir nicht funktionieren. Dazu müsstest Du Dir ein Vergleichsfunktion schreiben, die dann Komponentenweisestruct test_e
vergleicht. Sinnvoll wäre dann der Test aufa.i == b.i
, das vergleicht den Wert der beiden Integer Variablen. Für das Vergleichen von Strings gibt es die Funktionstrcmp
in der Standard Library.
-
Ah, ich denke, jetzt hab ich's herausgefunden:
#include <stdio.h> typedef struct test_e { int i; char *cp; } Test_E; Test_E get_test_e() { Test_E a = {5, "hallo"}; printf("%p\n", (void *)&a); printf("%p\n", (void *)a.cp); printf("%p\n", (void *)&(a.cp[2])); /* 0x7ffd1ffb1ee0 0x400654 0x400656 a und der Inhalt von a wird flach kopiert! */ return a; } int main() { Test_E b = get_test_e(); printf("%p\n", (void *)&b); printf("%p\n", (void *)b.cp); printf("%p\n", (void *)&(b.cp[2])); /* 0x7ffd1ffb1f10 0x400654 0x400656 b und der Inhalt von b wurde flach kopiert! */ return 0; }
Wieso haben char s nur so eine kurze Adresse?
-
@EinNutzer0 sagte in Wann darf man was aus einer Funktion nicht returnen?:
Wieso haben char s nur so eine kurze Adresse?
Der Zeiger verweist auf einen statischen Codeteil, in dem der konstante String "hallo" abgelegt worden ist. Dagegen befindet sich die Adresse von a und b auf dem Stack, der liegt üblicherweise an einer anderen Stelle im Adressraum.