Verschachtelte Strukturen, Union und Bitfelder

Gast #4896866
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
Moderator #4896928
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.
#4896930
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).
Gast #4896961
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;

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren