Forum: Mikrocontroller und Digitale Elektronik union mit bitfeld in struct in c


von Hannes (Gast)


Lesenswert?

Hi,

ich möchte in einer struktur:

typedef struct
{
     uint8_t * feld1[10];
     uint8_t * feld2[10];
     ...
     uint8_t * feld8[10];
     uint8_t feld1_ok   :1,
             feld2_ok   :1,
             ...
             feld3_ok   :1;
}felder;

gern eine weitere Variable vom typ 8 bit unterbringen die 
adresstechnisch genau an der stelle liegt wo auch die 8 einzelnen 
ok-Bits liegen.

typedef struct
{
     uint8_t * feld1[10];
     uint8_t * feld2[10];
     ...
     uint8_t * feld8[10];
     union
     {
         uint8_t feld1_ok   :1,
                 feld2_ok   :1,
                 ...
                 feld8_ok   :1;
         uint8_t alle;
     };
}felder;

wird nicht angemekkert aber funktioniert trotzdem nicht, habe ich das 
mit der union falsch verstanden, muss ich zuvor einen typen machen, oder 
kann ich das auch so in einem lösen?

Wenn ich dies geraffel einer Funktion übergebe, also darauf zeige:

felder datensatz;
felder * p_datensatz;

p_datensatz=&datensatz;

dann sollte ich doch so

*p_datensatz->feld1[0]='A';
p_datensatz->feld1_ok=1;

zugreifen können. Was habe ich vergessen?

Gruß,
H.

von Antwort (Gast)


Lesenswert?

Das Union wird schon falsch deklariert. Du hast ihm keinen Namen 
gegeben. Ein Union verhält sich im ersten Moment wie ein struct, nur das 
es nur eine der möglichen Variablen speichern kann. Du müsstest es also 
wie folgt verändern:
1
typedef struct
2
{
3
     uint8_t * feld1[10];
4
     uint8_t * feld2[10];
5
     ...
6
     uint8_t * feld8[10];
7
     union my union
8
     {
9
         uint8_t feld1_ok   :1,
10
                 feld2_ok   :1,
11
                 ...
12
                 feld8_ok   :1;
13
     };
14
}felder;
Ansprechen dann wie folgt:
1
p_datensatz->my_union_feld1_ok = 1;

von Antwort (Gast)


Lesenswert?

Hatte einen Tippfehler
1
p_datensatz->my_union.feld1_ok = 1;


Aber ich denke mal nicht das es sich so verhalten wird wie du denkst. 
Schließlich hast du nicht alle ok felder im union zur Verfügung.

von Hannes (Gast)


Lesenswert?

hey,

bin gerad hier:

http://cboard.cprogramming.com/c-programming/102978-union-struct-bit-fields.html

1)das mit deinem Underline im Zugriff ist unverständlich!?
2)der Name beim Struct steht aber nach der geschweiften klammer bei der 
union nicht?


Gruß,
H.

von Hannes (Gast)


Lesenswert?

>>verhalten wird wie du denkst<<

warum, 8 ok, uint8_t alle?

H

von Karl H. (kbuchegg)


Lesenswert?

Hannes schrieb:

> wird nicht angemekkert aber funktioniert trotzdem nicht, habe ich das
> mit der union falsch verstanden, muss ich zuvor einen typen machen, oder
> kann ich das auch so in einem lösen?

du musst zunächst die 8 Bit mittels einer Struktur zusammenfassen, ehe 
du dann mittels union, zu der Struktur dann einen uint8_t parallel legen 
kannst.

In einer union werden ALLE Elemente, egal wieviele, übereinander gelegt.

von Sven P. (Gast)


Lesenswert?

Es sei darauf hingewiesen, dass die einschlägigen C-Standards bezüglich 
Bitfeldern festlegen, dass nichts festgelegt ist :-)

von Hannes (Gast)


Lesenswert?

hmm...

teste gerad ein wenig rum...

warum muss ich die bitfeld bits denn noch mit einem struct 
zusammenfassen bevor ich sie über das Byte legen kann, sie sind doch 
schon in einem byte?

H.

von Huch (Gast)


Lesenswert?

Es gibt keine Sonderbehandlung von Bits in unions. Sie sind alternativ 
zu jedem anderen Eintrag innerhalb der union; also auch zu anderen 
Bits. Deswegen musst Du sie zusammenfassen, wenn sie insgesamt 
alternativ zu anderen Elementen der union sein sollen.

von Hannes (Gast)


Lesenswert?

ich habe das mal alles nachgepflegt:


typedef struct
{
     uint8_t * feld1[10];
     uint8_t * feld2[10];
     ...
     uint8_t * feld8[10];
     union
     {
         struct
         {
             uint8_t feld1   :1,
                     feld2   :1,
                     ...
                     feld8   :1;
         }bit;
         uint8_t alle;
     }ok;
}felder;

Zugriff mache ich so:

felder datensatz;
felder * p_datensatz;

p_datensatz=&datensatz;

*p_datensatz->feld1[0]='A';
p_datensatz->ok.bit.feld1=1;
p_datensatz->ok.alle=0xFF;

Das scheint zu funktionieren, ich mache das gerade im MS Studio, dort 
erscheinen die Bits dann als 32 bit variablen dargestellt deren bits 
dann alle auf 1 gehen. Da man in dem Fall die Adresse nicht sehen kann 
bin ich nicht 100%ig sicher, das die bits und die "gesamt" variable auch 
wirklich übereinander liegen und das Bitfeld auch greift.

Habe ich es denn richtig umgesetzt?
gibt es eine Möglichkeit das .bit. aus der Zugriffstruktur heraus zu 
bekommen? Ich würde die Ebene gern sparen.

Gruß und vielen Dank bis hierher,
H.

von Klaus W. (mfgkw)


Lesenswert?

Hannes schrieb:
> gibt es eine Möglichkeit das .bit. aus der Zugriffstruktur heraus zu
> bekommen? Ich würde die Ebene gern sparen.

Der gcc erlaubt auch anonyme unions; wenn es nicht portabel sein
muß (was es ja faktisch gar nicht ist), geht es auch ohne.

von Huch (Gast)


Lesenswert?

>Da man in dem Fall die Adresse nicht sehen kann
>bin ich nicht 100%ig sicher, das die bits und die "gesamt" variable auch
>wirklich übereinander liegen und das Bitfeld auch greift.

Nun, das ist ja genau die interpretation von "union". Alle Einträge 
liegen an der selben Adresse!
Aber Du kannst selbstverständlich auch die Adresse nachprüfen.

& p_datensatz->ok.bit

und

& p_datensatz->ok.alle

müssen das selbe ergeben.

>gibt es eine Möglichkeit das .bit. aus der Zugriffstruktur heraus zu
>bekommen? Ich würde die Ebene gern sparen.

Nein.

Ist das wirklich beabsichtig, das Du Vektoren von Zeigern anlegst?

     uint8_t * feld1[10];

Ich frage weil Du den nicht alloziierten Vektorelementen dann Zeichen 
zuweist. Oder fehlt die Alloziierung nur in Deinem Zitat?

von Hannes (Gast)


Lesenswert?

>>Ist das wirklich beabsichtig, das Du Vektoren von Zeigern anlegst?<<

nein, da habe ich mich versehen. Es sind strings, Felder von chars. Ist 
mir beim erstellen des Beispiels da rein gerutscht...


>>& p_datensatz->ok.bit<<

töffel, daran habe ich nicht gedacht. Hab das in der Zwischenzeit anders 
nachgewiesen, aber so ists natürlich noch einfacher, danke :-)

Dann habe ich alles was ich brauche, danke.
H.

Ps.: die Anspielung auf die -nicht kompatibilität- ist doch auf die MSB 
LSB Geschichte bei Bitfeldern bezogen, oder?
Dann stimmt die Aussage meiner Meinung nach nur dann wenn man der 
Bitcodierung der Variablen "alle" keine Wertung in Bezug auf die 
einzelnen Bits bei der Zuweisung eines Wertes beipflichtet. Sie wird nur 
zum resetten aller Bits benutzt.
Wenn man diese Struktur zudem nicht über eine Systemunabhängige 
Schnittstelle wie Ethernet oder ähnliches an ein anderes System mit 
selbiger Struktur im code übermittelt, erwarte ich damit keine Probleme.

von Huch (Gast)


Lesenswert?

>Ps.: die Anspielung auf die -nicht kompatibilität- ist doch auf die MSB
LSB Geschichte bei Bitfeldern bezogen, oder?

Das bezog sich auf die Sprachkompatibilität. In C sind anonyme 
Strukturen nicht möglich. In C++ allerdings schon. Da der GCC beides 
kann lässt er, falls Du nicht ausdrücklich z.B. C99 festgelegt hast auch 
anonyme Strukturen in C zu.

Was die Zuordnung von Bits des Bitfeldes zu Bits des alternativen uint8 
betrifft, so ist im Sprachstandard nichts zugesichert. Das ist soweit 
richtig, hat aber nichts damit zu tun ob anonyme Strukturen zulässig 
sind oder nicht. Deswegen sind solche Dinge nicht "transportabel" (das 
ist hier der korrekte Begriff im Ggs. zu kompatibel).

Dennoch ist das Verhalten eines Compilers auf einer Maschine in der 
Regel konsistent implementiert. D.h. das er die Bits immer in der selben 
Reihenfolge anordnet.

von Huch (Gast)


Lesenswert?

Sorry. "Transportabel" ist eigentlich auch nicht ganz üblich. "Portabel" 
ist hier besser. Ist beides das selbe, aber was anderes als 
"Kompatibel".

von Rolf Magnus (Gast)


Lesenswert?

Huch schrieb:
> Was die Zuordnung von Bits des Bitfeldes zu Bits des alternativen uint8
> betrifft, so ist im Sprachstandard nichts zugesichert.

Und für unions ist dort festgelegt, daß man auf gar keinen Fall ein 
anderes Element lesen darf als das, das man zuletzt geschrieben hat.

von Marco U. (Gast)


Lesenswert?

Sofern ich mich erinnern kann werden, selbst wenn man nur 1 Bit 
verwendet, dennoch als kleinste Einheit sizeof(int) reserviert. Die 
restlichen Bit des Byte "liegen brach". Was die Verwendung von 
Bitfeldern mit geringer Größe meiner Meinung nach obsolet macht.

Aus C von A bis Z von Jürgen Wolf

struct robo {
   unsigned int sensor1:1;
   unsigned int sensor2:1;
   unsigned int sensor3:1;
   unsigned int schalter:1;
   unsigned int Ausgabe:4;
} Roboter1;

Jetzt benötigt die Struktur im Grunde nur noch acht Bits (ein Byte). 
Wenn Sie allerdings mit sizeof prüfen, werden Sie feststellen, dass 
dieses Bitfeld trotzdem vier Byte belegt. Dies liegt daran, dass das 
kleinstmögliche Rechnerwort, das der Compiler für ein Bitfeld 
reserviert, sizeof(int) groß ist. Die restlichen drei Bytes in diesem 
Beispiel sind praktisch leer. Gleiches gilt hierbei natürlich auch, wenn 
Sie beispielsweise ein Bitfeld mit 40 Bits (fünf Bytes) erstellen. Hier 
muss der Compiler ein weiteres Rechnerwort (sizeof(int)) reservieren, 
sodass das fünfte Byte am Anfang des nächsten Rechnerworts liegt und 
somit insgesamt 8 Bytes benötigt werden.

Quelle: 
http://openbook.galileocomputing.de/c_von_a_bis_z/015_c_strukturen_013.htm#mj2f57db5965c2ac0ab2c8d3d97f038272

Gruß
Marco

von Rolf Magnus (Gast)


Lesenswert?

Marco Ullrich schrieb:
> Sofern ich mich erinnern kann werden, selbst wenn man nur 1 Bit
> verwendet, dennoch als kleinste Einheit sizeof(int) reserviert.

Ja, wenn du als Typ für die Elemente int angibst. Abhängig vom Compiler 
sind aber durchaus auch kleinere Typen erlaubt (ein Compiler muß 
mindestens mit bool, int und unsigned int umgehen können, darf aber auch 
beliebige andere Integertypen unterstützen). Folgendes Programm gibt bei 
mir
1
1
 aus:
1
#include <stdio.h>
2
3
struct bitfield
4
{
5
    unsigned char a : 1;
6
    unsigned char b : 2;
7
    unsigned char c : 3;
8
};
9
10
int main()
11
{
12
    printf("%d\n", sizeof(struct bitfield));
13
}

Da sowieso so ziemlich alle Eigenschaften von Bitfeldern höchst 
compilerspezifisch sind, macht es auch nichts mehr aus, wenn man sich 
auch darauf verläßt, daß das so geht.

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.