Forum: Compiler & IDEs union, struct - Verständnissproblem


von Michael L. (eagle87)


Lesenswert?

Hallo,
ich versuche ein Beispielprogramm von Atmel nachzuvollziehen und zu 
verstehen. Dabei bin ich auf die Datentypen union und struct gestoßen, 
die ich bisher noch nicht kannte. Dass bei union sich zwei verschiedene 
Variablen den selben Speicherplatz teilen und dass mit struct eine 
Struktur, die aus mehreren Variablen aufgebau ist, entsteht hab ich 
schon rausgefunden.
1
union USI_TWI_state
2
{
3
  uint8_t errorState;
4
  struct
5
  {
6
    uint8_t addressMode    : 1;
7
    uint8_t masterWriteDataMode  : 1;
8
    uint8_t unused      : 6;
9
  };
10
}  USI_TWI_state;
Aber nun zu den Fragen:
Wieso steht der Name für union, also USI_TWI_state, vor und hinter der 
geschweiften Klammer?
Was bedeuten bei struct die Zahlen am Ende der einzelnen Zeilen (z.B. ": 
1;")

Gruß
Michael

von Rufus Τ. F. (rufus) Benutzerseite


Lesenswert?

Michael L. schrieb:
> Wieso steht der Name für union, also USI_TWI_state, vor und hinter der
> geschweiften Klammer?

Das erste deklariert den Typ der Union, das zweite legt eine Variable 
dieses Typs an. Es ist ausgesprochen ungeschickt, die gleich zu 
benennen.

Michael L. schrieb:
> Was bedeuten bei struct die Zahlen am Ende der einzelnen Zeilen

Das ist ein Bitfeld, d.h. die Strukturelemente sind nur soviele Bit 
groß wie angegeben.

von Michael L. (eagle87)


Lesenswert?

> Das erste deklariert den Typ der Union, das zweite legt eine Variable
> dieses Typs an.

Ok. Mit dem zweiten Namen (von der Definition) wird ja auf die Variablen 
zugegriffen. Welche Bedeutung hat der erste Name (bei der Deklaration)? 
Oder ist das einfach eine Bezeichnung die danach nie wieder verwendet 
wird?

von Hmm (Gast)


Lesenswert?

>Oder ist das einfach eine Bezeichnung die danach nie wieder verwendet
wird?

Das ist die Bezeichnung der Struktur selbst.

Ich empfehle Dir die Lektüre eines C-Buches.

von Hmm (Gast)


Lesenswert?

Ooops. Der union natürlich.

von Rufus Τ. F. (rufus) Benutzerseite


Lesenswert?

Michael L. schrieb:
> Welche Bedeutung hat der erste Name (bei der Deklaration)?

Nun, damit kann man weitere Variablen des gleichen Typs anlegen, oder 
diesen Typ z.B. als Funktionsargument verwenden ...


Wird nur genau eine Variable benötigt, kann man den Namen auch 
weglassen, das heißt dann anonyme union.

von Horst (Gast)


Lesenswert?

mit dieser Konstruktion kannst du auf zwei verschiedene Formen auf die 
Statusvariable zugreifen.

entweder:
1. Über die Variable errorState oder
2. über das Bitfeld bzw. die Struktur

also
1. USI_TWI_STate.errorState //Zugriff auf die alle Flags
2. USI_TWI_state.adressMode //Zugruff auf das entsprechende Flag

hoffe, ich habs verständlich ausgedrückt!:)

von Fabian O. (xfr)


Lesenswert?

Die Bedeutung der beiden Namen wird klarer, wenn man es in zwei Schritte 
aufteilt. Mal ein einfacheres Beispiel:
1
struct xy_struct {
2
  uint8_t x;
3
  uint8_t y;
4
};
Das sagt dem Compiler, was ein "struct xy_struct" prinzipiell ist. Hier 
also, dass es zwei Variablen x und y vom Typ uint8_t enthält. Es wird 
noch keine Variable und damit Speicher reserviert, es ist eine reine 
Information für den Compiler.

Das Anlegen der Variable passiert hier:
1
struct xy_struct mein_xy1;
2
struct xy_struct mein_xy2;
Hier werden zwei Variablen vom Typ "struct xy_struct" angelegt. Dafür 
werden insgesamt vier Byte Speicher reserviert. Man kann auf ein 
einzelnes Element dann z.B. per mein_xy1.x zugreifen.

Man kann diese beiden Schritte auch in einen zusammenziehen:
1
struct xy_struct {
2
  uint8_t x;
3
  uint8_t y;
4
} mein_xy1;
Hier wurde deklariert, was ein "struct xy_struct" ist und gleichzeitig 
die Variable mein_xy1 mit diesem Typ angelegt.

Dadurch, dass die Struktur einen Namen hat, kann man später noch mehr 
Variablen davon anlegen:
1
struct xy_struct mein_xy2;
Oder auch eine Funktion definieren, die etwas mit dieser Struktur macht:
1
void print_x(struct xy_struct xy) {
2
  putchar(xy.x);
3
}

Das gleiche ist in Deinem Beispiel mit der Union der Fall. Dort wurde 
für den Namen der Union (des Typs) und für den Variablennamen der 
gleiche Bezeichner gewählt. Das ist wie gesagt ziemlich ungeschickt und 
sollte man nicht machen.

von Michael L. (eagle87)


Lesenswert?

Horst schrieb:
> mit dieser Konstruktion kannst du auf zwei verschiedene Formen auf die
> Statusvariable zugreifen.
>
> entweder:
> 1. Über die Variable errorState oder
> 2. über das Bitfeld bzw. die Struktur
>
> also
> 1. USI_TWI_STate.errorState //Zugriff auf die alle Flags
> 2. USI_TWI_state.adressMode //Zugruff auf das entsprechende Flag
>
> hoffe, ich habs verständlich ausgedrückt!:)

Hab noch nicht wirklich verstanden was du gemeint hast. War es Absicht 
dass du einmal STate und einmal state geschrieben hast?

@ Fabian O.
Vielen Dank für die Ausführliche Beschreibung. Das hat einges klarer 
gemacht.

Rufus Τ. Firefly schrieb:
> Wird nur genau eine Variable benötigt, kann man den Namen auch
> weglassen, das heißt dann anonyme union.

Ok, wenn ichs richtig verstanden hab ist dann in meinem Beispiel die 
Struktur "anonyme"

von Horst (Gast)


Lesenswert?

Nein, war keine Absicht! ;)
Was eine Union ist, ist dir klar oder?
Eine Union ist immer nur so groß, wie der größte Datentyp, der in der 
Union enthalten ist.

ich habe mal ein ähnliches Konstrukt in meinem Projekt verwendet:
[c]
typedef union
{
  int bufferSize[512];
  struct
  {
    int UZK[128];
    int IU[128];
    int IV[128];
    int IW[128];
  }adc;
}adc_buffer_union;

volatile adc_buffer_union Adc_BufferA;
[\c]


Wenn du jetzt z.b. auf das dritte Elemtent von UZK zugreifen möchtest, 
kannst du das auf zwei Arten tun:

Adc_BufferA.bufferSize[2] oder
Adc_BufferA.adc.UZK[2]

weiters Beispiel: Zugriff auf IU[5]

Adc_BufferA.bufferSize[133] oder
Adc_BufferA.adc.IU[5]


Beide Varianten enthalten jeweils diselben Daten.

in deinem Beispiel enthält die Struktur bzw. das Bifeld exakt dieselben 
Daten wie die Variable errorState.

USI_TWI_state.errorState = 2; bzw.
USI_TWI_state.masterWriteDataMode = 1; ist exakt daselbe.

von Michael L. (eagle87)


Lesenswert?

Ok, jetzt weiß ich was gemeint hast. Da sich bei union mehrere Variablen 
den selben Speicherplatz teilen, wird beim Verändern der einen Variablen 
zwangsweiße auch die andere mitverändert.

von Bronco (Gast)


Lesenswert?

Michael L. schrieb:
> Ok, jetzt weiß ich was gemeint hast. Da sich bei union mehrere Variablen den 
selben Speicherplatz teilen, wird beim Verändern der einen Variablen zwangsweiße 
auch die andere mitverändert.

Was zwar oft gemacht wird, aber eigentlich nicht ganz korret ist (Thema 
Aliasing):
Beitrag "Re: Kann man denn jetz das hi- und low-byte eines uint16_t effizient lesen in c?"

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.