Forum: Compiler & IDEs Verschachtelte Strukturen, Union und Bitfelder


von Michael B. (Gast)


Lesenswert?

Hallo zusammen,

habe ein Problem beim Anlegen eines verschachtelten Bitfeldes mit 
Strukturen und Union.

Ziel ist folgendes:
Das gesamte "Konstrukt" soll/darf nur 1 Byte groß sein.
Die Bits 5, 6 und 7 sind ein einzelne Bitfelder (hier: c, b und a).
Die Bits 0+1 (f) sowie 2+3+4 (e) bilden jeweils ein weiteres 
(Zahlen)Feld.
Diese, also die Bits 0 bis 4, sollen zeitgleich auch einen "Gesamtwert" 
repräsentieren (d). Alles zusammen ist eine Kenngröße (g).
1
Bits   7   6   5   4   3   2   1   0
2
     ----------------------------------
3
     |               g                |
4
     ----------------------------------
5
     | a | b | c |         d          |
6
     ----------------------------------
7
                 |     e     |    f   |
8
                 ----------------------

In C sieht das ganze bei mir so aus:
1
typedef union
2
{
3
  struct
4
  {
5
    uint8_t                a : 1;
6
    uint8_t                b : 1;
7
    uint8_t                c : 1;
8
    union
9
    {
10
      struct
11
      {
12
        uint8_t            f : 2;
13
        uint8_t            e : 3;
14
      };
15
      uint8_t              d : 5;
16
    }; 
17
  };
18
  uint8_t                  g;
19
}  TypeID;

Der so definierte Datentyp ist jedoch nicht 1 Byte, sondern 2 Byte groß 
(sizeof(TypeID))! :-O

Begründet liegt das irgendwie an dem inneren Union. Definiere ich das 
ganze so:
1
typedef union
2
{
3
  struct
4
  {
5
    uint8_t                a : 1;
6
    uint8_t                b : 1;
7
    uint8_t                c : 1;      
8
    uint8_t                d : 5; 
9
  };
10
  uint8_t                  g;
11
}  TypeID;
oder so
1
typedef union
2
{
3
  struct
4
  {
5
    uint8_t                a : 1;
6
    uint8_t                b : 1;
7
    uint8_t                c : 1;      
8
    uint8_t                f : 2;
9
    uint8_t                e : 3;
10
  };
11
  uint8_t                  g;
12
}  TypeID;

beträgt die Größe nur 1 Byte.
Klar kann ich jetzt Makros definieren um "d" maskieren und shiften um 
"e" und "f" zur erhalten, das Ganze allerdings direkt über einen Zugriff 
auf Variablen des Datentyps zu lösen ware mir um ein vielfaches lieber.

Wie bekomme ich denn den Datentyp auf 1 Byte !?

Danke für eure Hilfe!

Grüße
Michael

von A. S. (Gast)


Lesenswert?

#pragma Pack, alignment oder ähnliches in deinem Compilerhandbuch 
nachschlagen.

Bei mir ist alles 1 Byte groß

von A. S. (Gast)


Lesenswert?

Sorry, deine erste struct muss Union heissen.

Wenn du mit dem 4ten bit beginnen willst, dann 3bit ohne Namen 
reservieren.

von (prx) A. K. (prx)


Lesenswert?

Ich würde in eine Bitfeld-Struct nicht noch eine weitere 
Bitfeld-Struct/Union schachteln.

von Michael B. (Gast)


Lesenswert?

Achim S. schrieb:
> Sorry, deine erste struct muss Union heissen.
>
> Wenn du mit dem 4ten bit beginnen willst, dann 3bit ohne Namen
> reservieren.

Wie du meinen?

von Yalu X. (yalu) (Moderator)


Lesenswert?

Mit dieser Deklaration werden beim GCC die Bitfelder so angeordnet, wie
du es dir vorstellst:

1
typedef union
2
{
3
  struct
4
  {
5
    union
6
    {
7
      struct {
8
        uint8_t  d : 5; // Bit 0..4
9
        uint8_t  c : 1; // Bit 5
10
        uint8_t  b : 1; // Bit 6
11
        uint8_t  a : 1; // Bit 7
12
      };
13
      struct
14
      {
15
        uint8_t  f : 2; // Bit 0..1
16
        uint8_t  e : 3; // Bit 2..4
17
      };
18
    }; 
19
  };
20
  uint8_t        g;     // Bit 0..8
21
} TypeID;

Ein Garantie, dass die Anordnung für einen anderen Compiler ebenso ist,
gibt es aber nicht.

Edit:

Die Größe eines Datentyps ist immer ein ganzzahliges Vielfaches eines
Bytes. Du hast aber wahscheinlich erwartet, dass das dein inneres Struct
nur 5 Bit groß ist.

: Bearbeitet durch Moderator
von Mikro 7. (mikro77)


Lesenswert?

1
#include <stdio.h>
2
#include <inttypes.h>
3
4
union U
5
{
6
  uint8_t g ;
7
  struct
8
  {
9
    uint8_t d : 5 ;
10
    uint8_t c : 1 ;
11
    uint8_t b : 1 ;
12
    uint8_t a : 1 ;
13
  } abcd ;
14
  struct
15
  {
16
    uint8_t f : 2 ;
17
    uint8_t e : 3 ;
18
  } ef ;
19
} ;
20
21
int main()
22
{
23
  union U u ;
24
  u.g = 0x5d ;
25
  printf("%ld\n",sizeof(u)) ;
26
  printf("%x %x\n",u.ef.e,u.ef.f) ;
27
  printf("%x %x %x %x\n",u.abcd.a,u.abcd.b,u.abcd.c,u.abcd.d) ;
28
  return 0 ;
29
}
Ausgabe:
1
1
2
7 1
3
0 1 0 1d
Imho kann der Compiler aber alles mögliche draus machen. Undefined 
Behavior (at least IB).

von (prx) A. K. (prx)


Lesenswert?

Yalu X. schrieb:
> Ein Garantie, dass die Anordnung für einen anderen Compiler ebenso ist,
> gibt es aber nicht.

Bei einer big endian Maschine wird es so nicht funktionieren.

von (prx) A. K. (prx)


Lesenswert?

Mikro 7. schrieb:
> Undefined Behavior (at least IB).

Grösstenteils implementation defined behavior.

von A. S. (Gast)


Lesenswert?

Michael B. schrieb:
> Wie du meinen?


Ich sollte nie vom Handy schreiben...

Also: als erstes klären, ob er mit Bit0 oder mit bit7 anfängt.
1
typedef union
2
{
3
  struct
4
  {
5
    uint8_t                a : 1;
6
    uint8_t                b : 1;
7
    uint8_t                c : 1;
8
    uint8_t                d : 5;
9
  }a_d;
10
  
11
  struct
12
  {
13
      uint8_t              : 3;
14
      uint8_t            e : 3;
15
      uint8_t            f : 2;
16
  }ef;
17
  uint8_t                  g;
18
}  TypeID_MSBstart;
19
20
21
typedef union
22
{
23
  struct
24
  {
25
    uint8_t                d : 5;
26
    uint8_t                c : 1;
27
    uint8_t                b : 1;
28
    uint8_t                a : 1;
29
  }d_a;
30
  
31
  struct
32
  {
33
      uint8_t            f : 2;
34
      uint8_t            e : 3;
35
  }ef;
36
      
37
  uint8_t                  g;
38
}  TypeID_LSBstart;

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.