Wann darf man was aus einer Funktion nicht returnen?
-
@EinNutzer0
Wo wird beim Aufruf eine Kopie erstellt? Nirgends.
Jede Zuweisung einer Struktur impliziert eine Kopie aller seiner Elemente (außer FAM - ja wer weiß das schon? - naja es reicht ja, wenn ich das weiß).Und passend dazu ein Zitat des allwissenden (Vorsicht Ironie) Fachbuchautors Jürgen Wolf (Pfuscher JW) aus "C von A bis Z":
Folgende Wertzuweisung von Strukturen sollten Sie allerdings vermeiden:
struct { int a1; int a2; int a3; } werte1, werte2; werte1.a1 = 8; werte1.a2 = 16; werte1.a3 = 32; werte2 = werte1; // Bitte vermeiden Sie solche Zuweisungen.
Das ist in C zwar erlaubt, kann aber zu Fehlern führen, wenn ein Compiler dies nicht unterstützt. Sicherer wäre die folgende Möglichkeit:
memcpy(&werte2, &wert1, sizeof(werte1));
Zitat Ende.
Pfuscher JW impliziert hier also, dass ein C-Compilerbauer keine Ahnung vom Standard hat und nicht weiß, wie er solche "komplizierte" Regel fehlerfrei umsetzen soll.Ich hoffe, das nimmt dir zukünftig die Laune, C anhand von Büchern,Tutorials,Professoren zu erlernen.
A_Elem search_max(int *const a, const int count)
Hier ist const komplett überflüssig und suggeriert somit Falsches.
-
@Wutz sagte in Wann darf man was aus einer Funktion nicht returnen?:
außer FAM - ja wer weiß das schon? - naja es reicht ja, wenn ich das weiß
Für alle die sich fragen: Flexible Array Members. Der Größe bezüglich offene Array am Ende einer Struct. Der Benutzer ist dafür zuständig genügend Speicherplatz für eine Objekt einer solchen Struct zu beschaffen.
@EinNutzer0 sagte in Wann darf man was aus einer Funktion nicht returnen?:
Also doch Call By Value Result...
Würdest Du bitte mal im Bezug auf die Sprache C mit Calling Conventions aufhören?? Lies den Standard und sag' bescheid wenn Du etwas dazu findest. Viel Glück.
-
@Wutz sagte in Wann darf man was aus einer Funktion nicht returnen?:
Wo wird beim Aufruf eine Kopie erstellt? Nirgends
Das stimmt nicht, Aktualparameter werden durch Zuweisung an die Formalparameter kopiert.
Es wäre aber schön zu wissen, was genau bei einer Zuweisung geschieht. Ich muss mir mal den Disassembler anschauen, befürchte ich.
-
Und
@EinNutzer0 sagte in Wann darf man was aus einer Funktion nicht returnen?:
Call By Value Result
in C schonmal garnie-nicht.
A ParameterPassing mode, used in AdaLanguage to handle "IN OUT" parameters. In CallByValueResult, the actual parameter supplied by the caller is copied into the callee's formal parameter; the function is run; and the (possibly modified) formal parameter is then copied back to the caller.
nix "return".
-
@EinNutzer0 sagte in Wann darf man was aus einer Funktion nicht returnen?:
Es wäre aber schön zu wissen, was genau bei einer Zuweisung geschieht.
Dann lies den Standart.
@EinNutzer0 sagte in Wann darf man was aus einer Funktion nicht returnen?:
Ich muss mir mal den Disassembler anschauen, befürchte ich.
Nein. As-if.
-
@EinNutzer0
Du hast hier überhaupt keinen struct-Parameter der kopiert werden könnte.
-
§6.5.2.2 Function calls
4. An argument may be an expression of any complete object type. In preparing for the call to a function, the arguments are evaluated, and each parameter is assigned the value of the corresponding argument.102)102) A function can change the values of its parameters, but these changes cannot affect the values of the arguments. On the other hand, it is possible to pass a pointer to an object, and the function can then change the value of the object pointed to. A parameter declared to have array or function type is adjusted to have a pointer type as described in 6.9.1.
-
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.