mikrocontroller.net

Forum: Mikrocontroller und Digitale Elektronik C deklarations Porblem union/struct/pointer


Autor: Psiyou ... (psiyou)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo,

habe da ein Problem bei der Deklaration von einem struct/union.
Im Prinzip möchte ich etwas, das nach meinem wissen in C so nicht geht. 
Ein Struct welches eine Union beinhaltet, in der wiederum ein Pointer 
auf das übergeordnete Struct ist.
typedef union
{
  BYTE parameter[MAX_PARAMETER_LENGTH];
  MENU_ITEM* lower_menu;
}MENU_PARAMETER;

//menu item structure
typedef struct
{
  BYTE name[MAX_ITEM_NAME_LENGTH];
  BYTE (*realize)(BYTE* parameter);
  MENU_PARAMETER para;
}MENU_ITEM;
Habe also das Problem das jeweils das andere bereits vorher bekannt sein 
muss. Gibt es da irgend eine Möglichkeit das zu lösen?
Wie könnte man das in C realisieren?

Gruß

Autor: holger (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Such mal nach "verkettete Liste" oder "linked list"

Autor: Εrnst B✶ (ernst)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Oder nach "forward declaration"
struct MENU_ITEM_;

typedef union
{
  BYTE parameter[MAX_PARAMETER_LENGTH];
  struct MENU_ITEM_ * lower_menu;
}MENU_PARAMETER;

//menu item structure
typedef struct MENU_ITEM_
{
  BYTE name[MAX_ITEM_NAME_LENGTH];
  BYTE (*realize)(BYTE* parameter);
  MENU_PARAMETER para;
}MENU_ITEM;

Nebenbei: custom typedefs/#defines wie "BYTE" sollte man in neuem Code 
nicht mehr verwenden, spätestens seit dem C99 Standard sollte jeder 
Compiler eine stdint.h mitbringen, die für sowas z.B. unint8_t 
definiert.

Autor: holger (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
>unint8_t

Wie ist das denn definiert ? "Not an uint8_t" ?

SCNR

Autor: Psiyou ... (psiyou)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
@ holger
Das wollte ich hier vermeiden da ich dies nicht bei jedem Eintrag 
brauche.

@ Ernst Bachmann (ernst)
Danke, genau das habe ich gesucht :)
Allerdings ist mir die Syntax nicht ganz klar.
typedef struct MENU_ITEM_
{
  BYTE name[MAX_ITEM_NAME_LENGTH];
  BYTE (*realize)(BYTE* parameter);
  MENU_PARAMETER para;
}MENU_ITEM;

So wie ich das verstehe ist MENU_ITEM_ der Name des Stucts und MENU_ITEM 
der Name des neuen Datentypes?
Dachte bis jetzt immer bei dem typdef Konstrukt der Name vor dem ; 
sowohl für das Struct als auch den Datentype steht.

Betreff stdint.h:
Danke, das wusste ich nicht. Habe immer angenommen das es einfach nur 
eine häufig verwendete Variante ist. Muss aber gestehen das ich mich da 
nie schlau gemacht habe.

Autor: Simon K. (simon) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Du kannst dir das so merken: Die Syntax von typedef ist immer:
typedef <vorhandener datentyp> <neuer datentyp>
typedef struct MENU_ITEM_
{
  BYTE name[MAX_ITEM_NAME_LENGTH];
  BYTE (*realize)(BYTE* parameter);
  MENU_PARAMETER para;
}MENU_ITEM;

hier ist "struct MENU_ITEM_ {...}" der alte Datentyp und "MENU_ITEM" der 
neue Datentyp.

Autor: Rufus Τ. Firefly (rufus) (Moderator) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Nur mal so am Rande gefragt:
typedef union
{
  BYTE parameter[MAX_PARAMETER_LENGTH];
  MENU_ITEM* lower_menu;
} MENU_PARAMETER;

Das soll so sein? Diese union enthält entweder einen Pointer oder 
ein "BYTE"-Array? Ist das wirklich sinnvoll?

Wie findest Du beim Gebrauch Deines Datentyps MENU_ITEM heraus, ob die 
enthaltene Variable para einen Pointer auf ein anderes MENU_ITEM oder 
eben ein "BYTE"-Array enthält?

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

Bewertung
0 lesenswert
nicht lesenswert
Simon K. wrote:
> Du kannst dir das so merken: Die Syntax von typedef ist immer:
>
typedef <vorhandener datentyp> <neuer datentyp>

Das stimmt so nicht ganz. (Bei Arrays bzw. Funktionspointern
kommst du damit ins Schleudern).

Man kann sich das so merken:
Wie wird eine Variable definiert? Genau so schreibst du das hin.
Dann kommt noch ein typedef davor und der 'Variablenname' wird
damit zum Namen des neuen Datentyps.

Autor: Simon K. (simon) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Gut, da hast du auch wieder Recht.

Karl Heinz meint also zum Beispiel folgendes:
typedef array_t uint8_t[4];

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

Bewertung
0 lesenswert
nicht lesenswert
Simon K. wrote:
> Gut, da hast du auch wieder Recht.
>
> Karl Heinz meint also zum Beispiel folgendes:
>
> typedef array_t uint8_t[4];
> 

Äh, nein.
Nimm mal das typedef weg.
Dann steht da

array_t uint8_t[4];

Das ist aber keine gültige Variablendefinition, da array_t
kein Datentyp ist.

Anders rum wird ein Schuh draus.
Wie definierst du ein Array von 4 uint8_t?

uint8_t variable[4];

Anstatt 'variable' nimm jetzt einen anderen Namen, der dich
mehr an einen Datentyp erinnert.

uint8_t array_t[4];

das definiert array_t als Array von 4 Stück uint8_t.

Jetzt setzt du einfach einen typedef davor
typedef uint8_t array_t[4];
wodurch array_t (das was vorher der Variablenname war), zum Namen
des neuen Datentyps wird.

Selbiges bei Funktionspointern.

void (*pFunc) ( char );

pFunc ist ein Pointer auf eine Funktion, die einen char nimmt
und nichts liefert.

typedef void (*pFunc) ( char );

pFunc ist der Name eines Datentyps, der ein Funktionszeiger
ist, wobei die Funktion einen char annimmt und nichts liefert.

Autor: Psiyou ... (psiyou)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
@ Rufus t. Firefly (rufus) (Moderator)
Das ergibt sich aus dem Kontext. Habe als Übergabeparameter bei allen 
Funktionen einheitlich uint8_t*. Die Funktionspointer stehen in einem 
Array zusammen mit dem Parameter. Bei ein paar brauche ich an stelle 
eines Strings jedoch ein Pointer auf MENU_ITEM als Übergabewert. Deshalb 
der Umweg über die Union. die Entsprechende Funktion macht das ganze 
dann wieder rückgängig.
Leider nicht schön, aber eine bessere Lösung ist mir nicht eingefallen.

@  Karl heinz Buchegger (kbuchegg) (Moderator)
Danke für die ausführliche Erklärung, macht so eindeutig Sinn und ich 
kann es mir merken :)

Gruß an Alle

Autor: Sven P. (haku) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Bei Zeigern ists egal, wodrauf die zeigen. Die brauchen immer gleichviel 
Speicher, weshalb es auch kein Problem darstellt, sie rekursiv in Unions 
und Strukturen zu verwenden. Im Zweifelsfall tuts "void *".

Autor: Psiyou ... (psiyou)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
@  Sven Pauli (haku)
Ja, das stimmt.
Wie sieht das den aus wegen der Harvard Architektur vom Atmel?
Bekomme ich da Probleme (hab das leider gerade nicht hier zum testen)?
Wollte das Array im Flash speichern, und da die Funktionen ja auch im 
Flash liegen sollte das ja klappen. Würde ich das Array im SRAM 
speichern dürfte es hingegen schief gehen, oder?

Autor: Rolf Magnus (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
> Bei Zeigern ists egal, wodrauf die zeigen. Die brauchen immer
> gleichviel Speicher,

So ganz allgemein ist diese Aussage falsch, auch wenn es bei vielen 
Compilern so ist.

> Im Zweifelsfall tuts "void *".

Es ist in C garantiert, daß ein beliebiger Objektzeiger verlustlos nach 
void* und wieder zurück konvertiert werden kann. Funktionszeiger sind 
allerdings in Standard-C generell inkompatibel zu Objektzeigern und 
dürfen streng genommen eigentlich nicht mal mit Cast nach void* 
konvertierbar sein. Die meisten Compiler ignorieren diese Regel 
allerdings.

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.