Wann darf man was aus einer Funktion nicht returnen?
-
@EinNutzer0 sagte in Wann darf man was aus einer Funktion nicht returnen?:
Wie gesagt, die Frage ist ernstgemeint. Demzufolge würde ich mich auch über ernste Antworten freuen. Wer seine schlechte Laune an andere rauslassen muss, sollte sich nen Boxsack aufstellen, um sich erst mal abzureagieren.
A_Elem search_max(int *const a, const int count)
{
A_Elem ae;
int i = 0;
int max_index = 0;
for (; i < count; i++)
{
if (a[i] > a[max_index])
{
max_index = i;
}
}
ae.max_index = max_index;
ae.max = a[max_index];
ae.maxp = &a[max_index];
return ae;
}Wieso darf ich hier dann ae returnen?
Weil hier eine Strukturvariable beim return kopiert wird darfst du das machen.
Wenn die Strukturelemente auch alle Kopien sind und ausschließlich nichtfunktionslokale Daten referenzieren, darfst du sogar mit der Strukturkopie nach Funktionsaufruf unfallfrei weitermachen.
-
@Swordfish
Deine Aussage - es muss nur eine Kopie sein und alles wird gut - ist pauschal und somit falsch.
Und dir ein entsprechendes Beispiel zu präsentieren, spare ich mir jetzt mal.
-
Na dann verallgemeinern wir doch weiter. C kennt sowieso keine Referenzen. Was zurückgegeben wird muss (zumindest sollte) danach ein gültiger Wert sein. Ein Zeiger auf ein Objekt dessen Lebenszeit um ist ist es nicht.
-
@SeppJ sagte in Wann darf man was aus einer Funktion nicht returnen?:
ich spekuliere mal, dass du dies mit "Arraypointer" gemeint hast.
ja. Arraypointer == ein Pointer auf das erste Arrayelement
Aber ich versteh's nicht, wieso ich
ae
returnen DARF. Die Variableae
wird doch nach dem Verlassen vonsearch_max
weggeräumt.
-
@Wutz sagte in Wann darf man was aus einer Funktion nicht returnen?:
Weil hier eine Strukturvariable beim return kopiert wird darfst du das machen.
Also doch
Call By Value Result
...Es wird also zweimal eine Kopie erstellt, beim Aufruf und bei der Rückkehr. Wobei eine Kopie einer
struct
die gesamtestruct
ist... right?
-
@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?