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


von Psiyou .. (Gast)


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.
1
typedef union
2
{
3
  BYTE parameter[MAX_PARAMETER_LENGTH];
4
  MENU_ITEM* lower_menu;
5
}MENU_PARAMETER;
6
7
//menu item structure
8
typedef struct
9
{
10
  BYTE name[MAX_ITEM_NAME_LENGTH];
11
  BYTE (*realize)(BYTE* parameter);
12
  MENU_PARAMETER para;
13
}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ß

von holger (Gast)


Lesenswert?

Such mal nach "verkettete Liste" oder "linked list"

von Εrnst B. (ernst)


Lesenswert?

Oder nach "forward declaration"
1
struct MENU_ITEM_;
2
3
typedef union
4
{
5
  BYTE parameter[MAX_PARAMETER_LENGTH];
6
  struct MENU_ITEM_ * lower_menu;
7
}MENU_PARAMETER;
8
9
//menu item structure
10
typedef struct MENU_ITEM_
11
{
12
  BYTE name[MAX_ITEM_NAME_LENGTH];
13
  BYTE (*realize)(BYTE* parameter);
14
  MENU_PARAMETER para;
15
}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.

von holger (Gast)


Lesenswert?

>unint8_t

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

SCNR

von Psiyou .. (Gast)


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.
1
typedef struct MENU_ITEM_
2
{
3
  BYTE name[MAX_ITEM_NAME_LENGTH];
4
  BYTE (*realize)(BYTE* parameter);
5
  MENU_PARAMETER para;
6
}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.

von Simon K. (simon) Benutzerseite


Lesenswert?

Du kannst dir das so merken: Die Syntax von typedef ist immer:
1
typedef <vorhandener datentyp> <neuer datentyp>
1
typedef struct MENU_ITEM_
2
{
3
  BYTE name[MAX_ITEM_NAME_LENGTH];
4
  BYTE (*realize)(BYTE* parameter);
5
  MENU_PARAMETER para;
6
}MENU_ITEM;

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

von Rufus Τ. F. (rufus) Benutzerseite


Lesenswert?

Nur mal so am Rande gefragt:
1
typedef union
2
{
3
  BYTE parameter[MAX_PARAMETER_LENGTH];
4
  MENU_ITEM* lower_menu;
5
} 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?

von Karl H. (kbuchegg)


Lesenswert?

Simon K. wrote:
> Du kannst dir das so merken: Die Syntax von typedef ist immer:
>
1
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.

von Simon K. (simon) Benutzerseite


Lesenswert?

Gut, da hast du auch wieder Recht.

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

von Karl H. (kbuchegg)


Lesenswert?

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

Ä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.

von Psiyou .. (Gast)


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

von Sven P. (Gast)


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 *".

von Psiyou .. (Gast)


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?

von Rolf Magnus (Gast)


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.

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.