Forum: Mikrocontroller und Digitale Elektronik Eine Fkt. - mehrere Returnwerte


von return (Gast)


Lesenswert?

moin,

irgendwie bin ich immer und immerwieder vor dem Problem, dass ich gerne 
eine Funktion in C hätte, mit der ich mehrere Rückgabeparameter auf 
einmal zurückgeben kann.

Beispiel:
Ein Array nach dem kleinsten Wert durchsuchen und dessen Position im 
Array ebenfalls mit rausgeben.

Eine Bastellösung wäre, die beiden Werte jeweils als ein High- und 
Low-Byte zu betrachten und das zusammengesetzte Wort zu returnen...

Aber wie gesagt, dass wäre eine Bastellösung, die mir gerade so in den 
Sinn kommt und die irgendwie suboptimal ist, weil man immer noch eine 
zusätzliche Funktion brauch, um das wieder auseinander zu frickeln...

Wie löst ihr am elegantesten eine solche Aufgabenstellung?

mfg

von Timmo H. (masterfx)


Lesenswert?

Struct?

von Peter II (Gast)


Lesenswert?

Zeiger reingeben

von Thosch (Gast)


Lesenswert?

Wie von den Vorpostern schon extrem kurz umschrieben:
Das Stichwort heißt "call by reference".

Mehrere Parameter lassen sich nicht über den eigentlichen Rückgabewert 
der Funktion zurückgeben.
Stattdessen übergibst Du der Funktion beim Aufruf für die 
Rückgabeparameter einen oder mehrere Pointer auf beschreibbare 
Variablen, in denen die eigentliche Werte-Rückgabe erfolgt.

Du übergibst also im Funktionsaufruf für die Rückgabeparameter der 
Funktion einen Pointer auf die zu beschreibende Variable.

Diese kann z.B. auch ein Array oder Struct sein, womit man mit nur einem 
Pointer mehrere Parameter zurückgeben kann.

Innerhalb der Funktion dereferenzierst Du den übergebenen Pointer, um 
die verschiedenen Rückgabewerte zu speichern. Die Funktion schreibt also 
ihre Rückgabewerte direkt in das durch den Pointer adressierte Array 
oder Struct.

Über dieselbe Struktur kann man der Funktion natürlich auch Parameter 
übergeben, Array oder Struct müssen beim Funktionsaufruf ja nicht 
undefiniert sein. ;-)

So ist z.B. eine Funktion machbar, die eine 3 x 3 Matrix als Array (per 
Pointer darauf!) übergeben bekommt und diese Matrix, falls möglich, 
invertiert. Die Inverse Matrix wird dann wieder in dem Übergabe-Array 
abgelegt und der normale Rückgabewert der Funktion wird als Fehlercode 
genutzt, um zu signalisieren, daß die Matrix nicht invertierbar ist.

Gruß,
Thorsten

von Thosch (Gast)


Lesenswert?

Für Deine Funktion könnte das etwa so aussehen:
1
// Definition der Funktion
2
void search_minimum(uchar_t *p_minval, uchar_t *p_minidx, uchar_t arr)
3
{
4
    // lokale Variablen
5
    uint_t searchidx;
6
    ...
7
8
    // Minimum-Suche
9
    ...
10
11
    // Parameterrückgabe
12
    *p_minval = arr[searchidx];
13
    *p_minidx = sarchidx;
14
}
15
16
17
18
// Aufruf der Funktion     
19
uchar_t min_value;
20
uchar_t min_index;
21
uchar_t array[ARRAY_LEN];
22
23
search_minimum(&min_value, &min_index, array);


Gruß,
Thorsten

von Thosch (Gast)


Lesenswert?

nachtrag:
in der Fkt. sollte der searchindex natürlich auf vom Typ uchar_t sein...

von Gert (Gast)


Lesenswert?

Ja, Pointer ist die Lösung.
Hier einige Grundlagen zu Pointern in C:
http://et-tutorials.de/3368/pointer-in-c/

von Marwin (Gast)


Lesenswert?

Da merkt man, dass die Jungs die C erfunden haben, eher einen 
mathematischen Hintergrund hatten als dass sie Assembler-Hacker waren. 
Letztere haetten ganz selbstverstaendlich Funktionen mit mehreren 
Resultaten vorgesehen.

von Cyblord -. (cyblord)


Lesenswert?

Marwin schrieb:
> Da merkt man, dass die Jungs die C erfunden haben, eher einen
> mathematischen Hintergrund hatten als dass sie Assembler-Hacker waren.
> Letztere haetten ganz selbstverstaendlich Funktionen mit mehreren
> Resultaten vorgesehen.

Merkwürdig nur dass praktisch in allen Programmiersprachen Funktionen 
nur einen Rückgabewert haben.
Das hat doch mit den "Jungs" von C nichts zu tun. Die Anlehnung an die 
mathematische Funktion ist durchaus sinnvoll.

gruß cyblord

von Lothar M. (Firma: Titel) (lkmiller) (Moderator) Benutzerseite


Lesenswert?

Marwin schrieb:
> Da merkt man, dass die Jungs die C erfunden haben, eher einen
> mathematischen Hintergrund hatten als dass sie Assembler-Hacker waren.
> Letztere haetten ganz selbstverstaendlich Funktionen mit mehreren
> Resultaten vorgesehen.
In Assembler kann ich nicht mal 1 Wert zurückgeben, sondern muss von 
vorn herein sagen: ich erwarte den Wert an dieser Adresse (und sei es 
auch der Stack).

von Florian T. (grendal)


Lesenswert?

Alternativ kann man die Funktion einen Pointer auf ein Array zurückgeben 
lassen das 2 Einträge hat die dann Minimum und Position ausgeben.
Was die anderen nicht "beachtet" haben ist, dass deine Funktion noch 
irgendwoher wissen muss wie lang dein Array ist, brauchst also einen 
Zusätzlichen eingabeparameter.

Florian

von Michael M. (technikus)


Lesenswert?

Timmo H. schrieb:
> Struct?
Genau, am besten mit Typedef kombiniert:
1
typedef struct // neuen Datentyp mit der Struktur der Rückgabe definieren
2
{
3
  int index;
4
  float wert;
5
}  
6
RETURNSTRUCT;
7
8
RETURNSTRUCT funktion(void);

Servus
Michael

von Yalu X. (yalu) (Moderator)


Lesenswert?

Marwin schrieb:
> Da merkt man, dass die Jungs die C erfunden haben, eher einen
> mathematischen Hintergrund hatten als dass sie Assembler-Hacker waren.

Andersherum wird ein Schuh daraus:

Gerade diejenigen Sprachen, die etwas mathematisch angehaucht sind
(prominentestes Beispiel: Haskell), erlauben die Rückgabe von Tupeln.
Die Zerlegung des Tupels in einzelne Komponenten kann dank Pattern-
Matching im gleichen Aufwasch erfolgen. Beispiel:
1
sumprod x y = (x+y, x*y)  -- Funktion mit zwei Ergebnissen
2
3
(s, p) = sumprod 3 4      -- Anwendung ergibt s=7 und p=12

In vielen anderen Sprachen (Python, Ruby, Lua, Groovy ...) geht das ganz
ähnlich.

Bei den  C-Entwicklern hingegen stand nicht die reine Mathematik sondern
der reale Prozessor im Vordergrund. Eines der ursprünglichen Konzepte
bestand darin, Funktionswerte in einem (immer gleichen) Prozessorregis-
ter oder allenfalls einem Registerpaar (bei double) zurückzugeben. Die
Rückgabe mehrerer Werte (sei es als getrennte Werte oder zusammengefasst
in eine Struktur oder ein Array) war deswegen nicht vorgesehen. Struktu-
ren als Funktionswerte kamen erst später (mit ANSI-C), Arrays sind immer
noch nicht möglich.

Das Beispiel von oben ist in heutigem C zwar in ähnlicher Form möglich,
sieht aber recht holprig aus:
1
// Hilfsstruktur
2
3
struct SumProd {
4
  int sum, prd;
5
};
6
7
// Funktion mit zwei Ergebnissen
8
9
struct SumProd sumprod(int x, int y) {
10
  struct SumProd sp;
11
  sp.sum = x + y;
12
  sp.prd = x * y;
13
  return sp;
14
}
15
16
// Anwendung ergibt s=7 und p=12
17
18
  struct SumProd sp;
19
  int s, p;
20
21
  sp = sumprod(3, 4);
22
  s = sp.sum;
23
  p = sp.prd;

Deswegen bedient man sich auch heute noch meist der klassischen Methode
mit den Zeigerargumenten:
1
// Funktion mit zwei Ergebnissen
2
3
void sumprod(int x, int y, int *sum, int *prd) {
4
  *sum = x + y;
5
  *prd = x * y;
6
}
7
8
// Anwendung ergibt s=7 und p=12
9
  int s, p;
10
11
  sumprod(3, 4, &s, &p);

von Vuvuzelatus (Gast)


Lesenswert?

>Ein Array nach dem kleinsten Wert durchsuchen und dessen Position im
>Array ebenfalls mit rausgeben.

Der "richtige" Returnwert ist dann die Position und sonst nix. Auf die 
Rückgabe des Wertes kann man verzichten, denn um den zu wissen muss man 
ja nur "a[i]" schreiben (wenn i die Position ist und a das Array).

von Simon K. (simon) Benutzerseite


Lesenswert?

Vuvuzelatus schrieb:
>>Ein Array nach dem kleinsten Wert durchsuchen und dessen Position im
>>Array ebenfalls mit rausgeben.
>
> Der "richtige" Returnwert ist dann die Position und sonst nix. Auf die
> Rückgabe des Wertes kann man verzichten, denn um den zu wissen muss man
> ja nur "a[i]" schreiben (wenn i die Position ist und a das Array).

Das war auch mein erster Gedanke...

von W.S. (Gast)


Lesenswert?

Lothar Miller schrieb:
> In Assembler kann ich nicht mal 1 Wert zurückgeben, sondern muss...

Das ist Quatsch.
Man kann in Assembler so ziemlich alles zurückgeben. Das Ganze ist 
lediglich eine Frage der vereinbarten Implementierung.

So kann man bei Arm nachlesen, daß Funktionen dort im Prinzip sehr wohl 
mehrere Variablen zurückgeben können, weil es bei den dafür vorgesehenen 
Registern möglich ist. In Assembler wäre das nutzbar.

ABER: Es macht niemand davon Gebrauch, weil sowas in den einschlägigen 
Programmiersprachen nicht vorgesehen ist.

nochwas:

Gert schrieb:
> Ja, Pointer ist die Lösung.

Jaja, eine zwar benutzbare, aber schlechte Lösung. Anstatt mit Pointern 
um sich zu werfen, sollte man lieber über seine Lösungswege nachdenken 
und sich einen besseren Code ausdenken, der weitgehend ohne sowas 
auskommt. Pointer als Resultate sind grottenschlecht, denn worauf sollen 
sie zeigen? Auf Variablen auf dem Stack etwa?

W.S.

von Timmo H. (masterfx)


Lesenswert?

Naja Pointer zurückgeben meinte er wohl nicht, sondern vielmehr einen 
Pointer auf ein Array oder Struct übergeben und dort direkt 
reinschreiben. Also call by reference.
Das ist natürlich performanter als ein Struct zurückzugeben, da man sich 
so die ganze Rumkopiererei spart.
Hängt halt immer davon ab wie knapp die Ressourcen sind wie man das 
implementiert. Ich verwende beides, aber wenn ich mehrere Werte 
zurückgeben will, arbeite ich meist mit Pointer auf struct und schreibe 
direkt rein, anstatt ein Struct zurückzugeben.
Wenn ich z.B. überlege wenn ich meine "Einstellungen" die im EEPROM 
liegen auslese und vielleicht 30 Werte umfassen, dann würde ich nicht im 
Traum darauf kommen das ganze per return by value zu realisieren, 
zumindest nicht auf einem µC

von Simon K. (simon) Benutzerseite


Lesenswert?

W.S. schrieb:
> Gert schrieb:
>> Ja, Pointer ist die Lösung.
>
> Jaja, eine zwar benutzbare, aber schlechte Lösung. Anstatt mit Pointern
> um sich zu werfen, sollte man lieber über seine Lösungswege nachdenken
> und sich einen besseren Code ausdenken, der weitgehend ohne sowas
> auskommt.
Schwachsinn.

> Pointer als Resultate sind grottenschlecht, denn worauf sollen
> sie zeigen? Auf Variablen auf dem Stack etwa?
Warum denn nicht?

Schau mal als Beispiel in die Windows API, die ist voll mit sowas.
Mal zufallsmäßig was rausgepickt:
http://msdn.microsoft.com/en-us/library/windows/desktop/aa363260(v=vs.85).aspx

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.