Kann eine Funktion 2 Werte zurückgeben per Return?

Gast #635399
Lesenswert?

du kannst aber auch shiften, das machte man früher wenn man wenig 
speicher hatte gerne:

int dostuff(int r,int g,int b,int i)
{
int value = r | ( g << 8 ) | ( b << 16 ) | ( i << 24 );

return value;
}

die werte lassen sich dann wie folgt auseinander nehmen:

int color = dostuff(128,96,28,255);
int r = color & 255;
int g = ( color >> 8 ) & 255;
int b = ( color >> 16 ) & 255;
int i = ( color >> 24 ) & 255;

So habe ich früher gerne mal farben "kodiert" :). auch eine möglichkeit!
#635495
Lesenswert?

Das mit der Struct als Returnwert hört sich unheimlich an.
Legt der Compiler die Struktur vor Funktionsaufruf bereits auf dem Stack 
an?
Wie kann man die einzelnen Elemente dann erreichen?
Wird von der Funktion ein Zeiger zurückgegeben?
Wie funktioniert das genau, weis das einer?
#635509
Lesenswert?

1
#include <stdio.h>
2

3
struct Pair {
4
  int Component1;
5
  int Component2;
6
};
7

8

9
struct Pair foo( void )
10
{
11
  struct Pair RetVal;
12

13
  RetVal.Component1 = 5;
14
  RetVal.Component2 = 7;
15

16
  return RetVal;
17
}
18

19
int main()
20
{
21
  struct Pair Result;
22

23
  Result = foo();
24

25
  printf( "%d %d\n", Result.Component1, Result.Component2 );
26
}

> Legt der Compiler die Struktur vor Funktionsaufruf bereits auf
> dem Stack an?

Könnte er. Ist aber dem Compiler überlassen.

> Wie kann man die einzelnen Elemente dann erreichen?
So wie bei jeder anderen struct auch: Indem man die Komponente
angibt, auf die man zugreifen möchte

> Wird von der Funktion ein Zeiger zurückgegeben?
Nein. Im Funktionskopf steht, dass eine Struktur zurückgegeben
wird. Und genau das passiert auch. Zumindest dann, wenn der
Compiler keine Return-Value-Optimization macht.

> Wie funktioniert das genau, weis das einer?
Ja, dein Compiler.
#635683
Lesenswert?

Vom Aufbau her hätte ich mir das auch genau so vorgestellt.
Sieht allerdings nach einer ziehmlichen Kopierorgie aus.
Das lokale struct RetVal nuss ja bei return irgendwohin kopiert werden, 
wo es den Funktionsaufruf "überlebt". Und als zweites das kopieren in 
die Variable "Result" damit man auf die einzelnen Elemente Zugriff 
bekommt. Kann da der Kompiler überhaupt optimieren? Schließlich kann die 
Funktion von verschiedenen Stellen aus aufgerufen werden und die 
"Returnstruct" (woimmer sie auch liegen mag) muss damit Standardisiert 
sein.
#635702
Lesenswert?

Dirk S. wrote:
> Kann da der Kompiler überhaupt optimieren?

Und wie er das kann!
C++ lebt davon, dass es hier eine Möglichkeit zur Optimierung
gibt.

> Schließlich kann die
> Funktion von verschiedenen Stellen aus aufgerufen werden und die
> "Returnstruct" (woimmer sie auch liegen mag) muss damit Standardisiert
> sein.

Und?
Wenn der Compiler die NRVO (named return value optimization)
immer benutzt, ist das ja kein Problem.

Was ist die NRVO?
Kurz gesagt, der Compiler stellt das hier:
1
struct Pair foo( void )
2
{
3
  struct Pair RetVal;
4

5
  RetVal.Component1 = 5;
6
  RetVal.Component2 = 7;
7

8
  return RetVal;
9
}
10

11
int main()
12
{
13
  struct Pair Result;
14
  Result = foo();

so um
1
void foo( struct Pair* pTmp )
2
{
3
  pTmp->Component1 = 5;
4
  pTmp->Component2 = 7;
5
}
6

7
int main()
8
{
9
  struct Pair Result;
10

11
  foo(&Result);

et voila, keine Kopierorgie mehr.

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren