Hallo, ich habe eine Funktion, die ein struct zurückliefert. In diesem struct liegt ein String: typedef struct{ uint8_t id, parent, child, next, prev; uint8_t type; char name[MENU_STRING_LENGTH]; } menu_entry_t; menu_entry_t get_menu_entry(uint8_t id){ menu_entry_t res; strcpy(res.name, test_menu[id].name); res.id = test_menu[id].id; res.next = test_menu[id].next; res.prev = test_menu[id].prev; res.parent = test_menu[id].parent; res.child = test_menu[id].child; res.type = test_menu[id].type; return res; } Kann das so klappen? Vorallem bezüglich des Strings bin ich mir absolut nicht sicher, ob ich das so machen darf. MfG Henrik
Henrik wrote: > Kann das so klappen? Ja, kann und wird. > Vorallem bezüglich des Strings bin ich mir absolut > nicht sicher, ob ich das so machen darf. Doch, doch, ist schon in Ordnung. Der Knackpunkt ist, dass alles in einer Struktur eingebettet ist. Dadurch wird eine 1:1 byteweise Kopie bei der Übergabe gemacht. Egal ob die Struktur in eine Funktion hinein übergeben wird oder ob sie als Returnwert geliefert wird.
Ist dann das strcpy() in der Funktion, die das struct zurückliefern soll, überhaupt nötig? MfG Henrik
Henrik wrote: > Ist dann das strcpy() in der Funktion, die das struct zurückliefern > soll, überhaupt nötig? Ein test_menu Eintrag ist vom Datentyp menu_entry_t ? Wenn ja, dann ist das nicht nötig. Strukturen sind, anders als Arrays, zuweisbar und man hätte die Funktion auch so schreiben können:
1 | menu_entry_t get_menu_entry(uint8_t id){ |
2 | .... // ev. hier Fehlerabfrage der id |
3 | return test_menu[id]; |
4 | }
|
Struktur Elemente verhalten sich in C, so wie man sich das vorstellt: Sie können ohne Probleme als Ganzes zugewiesen werden und taugen daher auch als 'Call by Value' Argumente bzw. Returnwerte. Lediglich Arrays sind in C die große Ausnahme. Edit: Allerdings sollte man immer Bedenken, daß hier tatsächlich ein Kopiervorgang stattfindet. Man könnte sich daher überlegen, ob man den Prozessor nicht entlasten möchte und ganz einfach einen Pointer retourniert. Dsa hätte dann auch den Vorteil, daß sich der Fehlerfall durch die Rückgabe von NULL elegant erledigen lässt.
Wenn ich einen Zeiger zurückgeben möchte, dann kann ich die Variable res aber nicht in der Funktion deklarieren, oder? Weil dann ist sie doch nur lokal, und somit ist die Adresse, die ich auf dieses struct zurückgeben würde, doch außerhalb der Funktion nicht unbedingt gültig. MfG Henrik
Henrik wrote: > Wenn ich einen Zeiger zurückgeben möchte, dann kann ich die Variable res > aber nicht in der Funktion deklarieren, oder? Weil dann ist sie doch nur > lokal, und somit ist die Adresse, die ich auf dieses struct zurückgeben > würde, doch außerhalb der Funktion nicht unbedingt gültig. Das ist richtig. Solange du aber nur einen menu_entry_t aus deinem Array zurückliefern willst ohne ihn zb. zu modifizieren, benötigst du die Variable 'res' aber auch gar nicht.
1 | menu_entry_t* get_menu_entry(uint8_t id) |
2 | {
|
3 | if( id > MAX_NR_ENTRIES ) |
4 | return NULL; |
5 | |
6 | return &test_menu[id]; |
7 | }
|
kniffliger wird es, wenn der Eintrag aus dem Array vor der Rückgabe noch modifiziert werden soll. Dann, wie du richtig sagst, geht das so nicht. Dann musst du dich entscheiden: Wenn die Funktion einen Fehler in id nicht melden muss (weil du zb fehlerfrei programmierst) dann geht:
1 | menu_entry_t get_menu_entry(uint8_t id){ |
2 | menu_entry_t res; |
3 | |
4 | res = test_menu[id]; |
5 | |
6 | res.type = WAS_WEIS_ICH_WAS; |
7 | |
8 | return res; |
9 | }
|
Beachte: Ich lasse zuerst die komplette Struktur zuweisen und modifiziere erst dann den einen Wert. Das ist grundsätzlich besser, als alle Werte einzeln zu kopieren. Schon alleine aus dem Grund, weil ich keinen Struktur Member vergessen kann.
1 | res = test_menu[id]; |
bedeutet: kopiere das komplette Strukturobjekt, egal welche und wieviele Member das sind. Bei einer Strukturänderung ( zb. Member kommt hinzu) muss ich daher nicht darauf achten, dass diese Funktion diese Änderung berücksichtigen muss. Der Compiler kümmert sich darum, dass auch wirklich das komplette Struktur-Objekt kopiert wird. Wenn die Funktion aber in der Lage sein soll, einen Fehler zu melden, dann macht man das so, dass die Funktion bereits einen Eingangspointer erwartet, der auf eine Variable zeigen muss, in dem die Funktion das Ergebnis ablegen soll. Zusätzlich benutzt man dann den Returnwert um Erfolg oder Misserfolg anzuzeigen:
1 | menu_entry_t* get_menu_entry(uint8_t id, menu_entry_t* res) |
2 | {
|
3 | if( id > MAX_NR_ENTRIES ) |
4 | return NULL; |
5 | |
6 | *res = test_menu[id]; |
7 | res->type = WAS_WEIS_ICH_WAS; |
8 | |
9 | return res; |
10 | }
|
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
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.