www.mikrocontroller.net

Forum: Compiler & IDEs struct und char[] als Rückgabe


Autor: Henrik (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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.

Autor: Henrik (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ist dann das strcpy() in der Funktion, die das struct zurückliefern 
soll, überhaupt nötig?

MfG
Henrik

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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:
menu_entry_t get_menu_entry(uint8_t id){
  .... // ev. hier Fehlerabfrage der id
  return test_menu[id];
}

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.

Autor: Henrik (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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.
menu_entry_t* get_menu_entry(uint8_t id)
{
  if( id > MAX_NR_ENTRIES )
    return NULL;

  return &test_menu[id];
}

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:
menu_entry_t get_menu_entry(uint8_t id){
  menu_entry_t res;

  res = test_menu[id];

  res.type = WAS_WEIS_ICH_WAS;

  return res;
}

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.
  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:
menu_entry_t* get_menu_entry(uint8_t id, menu_entry_t* res)
{
  if( id > MAX_NR_ENTRIES )
    return NULL;

  *res = test_menu[id];
  res->type = WAS_WEIS_ICH_WAS;

  return res;
}

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.