Forum: Compiler & IDEs Union und Bitfelder


von Robert M. (andro86)


Lesenswert?

Hallo zusammen, ich hätte mal eine Frage zu Unions und Bitfeldern.

Ich sehe mir gerade einen Code an in dem prinzipiel folgendes drin 
steht:
1
   typedef union{
2
  
3
       struct{
4
         uint8_t dir  : 1;
5
         uint8_t evt  : 7;
6
       };
7
8
   }eventByte;

1
verstehe ich das richtig, dass wenn man die union weglässt, sich die folgende Speicherbelegung ergibt?
2
3
Speicheraddrese Bit 7   6   5   4   3   2   1   0
4
  0x000           |   |   |   |   |   |   |   |dir|
5
  0x001           |   |evt|evt|evt|evt|evt|evt|evt|
6
7
8
mit union:
9
10
Speicheraddrese Bit 7   6   5   4   3   2   1   0
11
  0x000           |   |evt|evt|evt|evt|evt|evt|dir|

Mir geht es hier rein ums Verständnis.

: Bearbeitet durch User
von dunno.. (Gast)


Lesenswert?

die 8 bit passen komplett in das uint8_t, also würde ich im ersten fall 
eher sowas zu erwarten

0x000 |evt|evt|evt|evt|evt|evt|evt|dir|


bei dem union mit einem einzigen typ muss ich aber passen. sicher dass 
da nicht noch ein uint8_t mit drin steckt?

von Robert M. (andro86)


Lesenswert?

dunno.. schrieb:
> die 8 bit passen komplett in das uint8_t, also würde ich im ersten fall
> eher sowas zu erwarten
>
> 0x000 |evt|evt|evt|evt|evt|evt|evt|dir|
>
>
> bei dem union mit einem einzigen typ muss ich aber passen. sicher dass
> da nicht noch ein uint8_t mit drin steckt?

sry, code war net vollständig. Es fehlt wirklich noch ein unit8_t, siehe 
nachfolgend!
1
[c]
2
   typedef union{
3
  
4
       struct{
5
         uint8_t dir  : 1;
6
         uint8_t evt  : 7;
7
       }uint8_t Byte;
8
9
   }eventByte;
[/c]

Also sobald ich mein Bitfeld mit einer union "übermantle" setzt mir der 
Compiler die Bitfelder in Byte richtig zusammen?

von fop (Gast)


Lesenswert?

Nein.

Die Speicherbelegung könnte so aussehen :
1
Speicheraddrese Bit 7   6   5   4   3   2   1   0
2
  0x000           |dir|evt|evt|evt|evt|evt|evt|evt|
3
  0x001           |   |   |   |   |   |   |   |   |
Das bleibt nämlich ein Struct. Die Union ist mit einem Mitglied wie bei 
Dir nur zusätzlicher Schreibaufwand.
1
   typedef union{
2
       struct{
3
         unsigned dir  : 1;
4
       };
5
       struct{
6
         unsigned evt  : 7;
7
       };
8
   }eventByte;

ist eine Union aus 2 Structs, die sich dann den Speicher teilen.

Aber Vorsicht : die genaue Anordnung im Speicher bleibt Sache des 
Compilers.

von dunno.. (Gast)


Lesenswert?

naja, du "übermantelst" das struct in der union mit einem uint8_t, und 
kannst die union dann verwenden als wäre es ein einziges uint8_t (ist es 
ja im speicher auch).. :)

von Robert M. (andro86)


Lesenswert?

fop schrieb:
> Nein.
>
> Die Speicherbelegung könnte so aussehen :
>
1
> Speicheraddrese Bit 7   6   5   4   3   2   1   0
2
>   0x000           |dir|evt|evt|evt|evt|evt|evt|evt|
3
>   0x001           |   |   |   |   |   |   |   |   |
4
>
> Das bleibt nämlich ein Struct. Die Union ist mit einem Mitglied wie bei
> Dir nur zusätzlicher Schreibaufwand.

Ok mir ging es in erster Linie darum zu verstehen, ob durch das 
zusammenlegen meiner struct-Elemente, Bit 0 von "evt" durch "dir" 
überschrieben werden könnte.

Was ich im Code anstrebe könnte so aussehen:
1
typedef struct EVENT
2
{
3
  union
4
  {
5
    struct
6
    {
7
      uint8_t dir     : 1;  
8
      uint8_t evtType : 7;
9
10
    }uint8_t EVENT1;
11
  };
12
13
  union
14
  {
15
    struct
16
    {
17
      uint8_t dir     : 1;  
18
      uint8_t evtType : 7;
19
20
    }uint8_t EVENT2;
21
  };
22
23
}__attribute__ ((packed));

Macht es hierbei Sinn das Attribut packed zu verwenden? Könnte ich damit 
die nachfolgende Speicherbelegung erreichen?
1
Speicheraddrese Bit 7   6   5   4   3   2   1   0
2
    0x000           |dir|evt|evt|evt|evt|evt|evt|evt| -- EVENT1
3
    0x001           |dir|evt|evt|evt|evt|evt|evt|evt| -- EVENT2

Ich versuche ein Konstrukt zu erschaffen, dass so wenig Speicher wie 
möglich in Anspruch nimmt.

von A. S. (Gast)


Lesenswert?

Robert M. schrieb:
1
> struct
2
>     {
3
>       uint8_t dir     : 1;
4
>       uint8_t evtType : 7;
5
> 
6
>     }uint8_t EVENT2;
bist Du sicher, dass das geht?
Fehlt da vielleicht ein Semikolon vor uint8_t und das struct bleibt dann 
unbenamt weil die Elemente eindeutig sind?

Robert M. schrieb:
> Ich versuche ein Konstrukt zu erschaffen, dass so wenig Speicher wie
> möglich in Anspruch nimmt.

Dann beschreib doch, wie es aussehen soll. Prinzipiell ist es möglich, 
Arrays von 8 Bit anzulegen, die jeweils 1 bit dir und 7 bit event haben. 
Ob Union, Structs oder Bitschieben für Dich und Deinen Prozessor das 
beste ist, wird man sehen.

von Bummsfallera (Gast)


Lesenswert?

fop schrieb:
> Aber Vorsicht : die genaue Anordnung im Speicher bleibt Sache des
> Compilers.

Das möchte ich nochmal hervorheben, weil es unions fast nutzlos macht.

Beispiel 1:
Wenn man zum Beispiel Bitfelder mittels Union in eine uint8_t über UART 
schickt und dann wieder auspackt, stimmt der Inhalt nicht zwingend, weil 
der PC die Bits anders einreiht als der Controller.
So ist es mir ergangen.

Beispiel 2:
Man deklariert sich Bitfelder mit Unions für die I2C-Kommunikation mit 
z.B. einem Temperatursensor. Der hat ja z.B. ein Statusregister mit 
viele Einzelbits drin - praktisch: Man kann sich die Bits ohne Masken 
und schieben aus dem Union ziehen. Klappt auch, und ist schnell.
Aber wehe man portiert den Code auf einen anderen Controller. Dann wird 
es unlustig.

Daher Vorsicht mit unions.

Das ist sehr, sehr schade, denn sie könnten so nützlich sein!

von union jack (Gast)


Lesenswert?

Hallo,

also entweder du verzichtest ganz auf das union[}
Beispiel 1:
1
#include <stdint.h>
2
#include <stdlib.h>
3
#include <stdio.h>
4
5
typedef struct
6
{
7
   struct
8
   {
9
      uint8_t dir:1;
10
      uint8_t evt:7;
11
   } event1;
12
13
   struct
14
   {
15
      uint8_t dir:1;
16
      uint8_t evt:7;
17
   } event2;
18
} event;
19
20
event events;
21
22
int main (void)
23
{
24
    printf ("size of events: %ld %p %p\n", sizeof(events), &events.event1, &events.event2);
25
26
    while (1)
27
    {
28
        printf ("evt1:%02X dir1:%02X evt2:%02X dir2:%02X\n", events.event1.evt,
29
                                                             events.event1.dir,
30
                                                             events.event2.evt,
31
                                                             events.event2.dir);
32
33
        if ((events.event1.evt++ & 0x03) == 0x03) events.event2.dir--;
34
        if ((events.event2.evt-- & 0x03) == 0x03) events.event1.dir++;
35
    }
36
37
    return (0);
38
}
1
 ./tst 
2
size of events: 2 0x601039 0x60103a
3
evt1:00 dir1:00 evt2:00 dir2:00
4
evt1:01 dir1:00 evt2:7F dir2:00
5
evt1:02 dir1:01 evt2:7E dir2:00
6
evt1:03 dir1:01 evt2:7D dir2:00
7
evt1:04 dir1:01 evt2:7C dir2:01
8
evt1:05 dir1:01 evt2:7B dir2:01
9
evt1:06 dir1:00 evt2:7A dir2:01
10
evt1:07 dir1:00 evt2:79 dir2:01
11
evt1:08 dir1:00 evt2:78 dir2:00
12
evt1:09 dir1:00 evt2:77 dir2:00
13
evt1:0A dir1:01 evt2:76 dir2:00
14
evt1:0B dir1:01 evt2:75 dir2:00
15
evt1:0C dir1:01 evt2:74 dir2:01
16
evt1:0D dir1:01 evt2:73 dir2:01
17
evt1:0E dir1:00 evt2:72 dir2:01
18
evt1:0F dir1:00 evt2:71 dir2:01

oder du hilfst ihm, seine Bestimmung zu erfüllen:

Beispiel 2:
1
#include <stdint.h>
2
#include <stdlib.h>
3
#include <stdio.h>
4
5
typedef struct
6
{
7
    union
8
    {
9
        struct
10
        {
11
            uint8_t dir:1;
12
            uint8_t evt:7;
13
        };
14
15
        uint8_t val;   
16
    } event1;
17
18
    union
19
    {
20
        struct
21
        {
22
            uint8_t dir:1;
23
            uint8_t evt:7;
24
        };
25
26
        uint8_t val;   
27
    } event2;
28
} event;
29
30
event events;
31
32
int main (void)
33
{
34
    printf ("size of events: %ld %p %p\n", sizeof(events), &events.event1, &events.event2);
35
36
    while (1)
37
    {
38
        printf ("val1:%02X dir1:%02X evt1:%02X val2:%02X dir2:%02X evt2:%02X\n", events.event1.val,
39
                                                                                 events.event1.dir,
40
                                                                                 events.event1.evt,
41
                                                                                 events.event2.val,
42
                                                                                 events.event2.dir,
43
                                                                                 events.event2.evt);
44
45
        if ((events.event1.val++ & 0x03) == 0x03) events.event2.dir++;
46
        events.event2.evt++;
47
    }
48
49
    return (0);
50
}
1
./tst1 
2
size of events: 2 0x601039 0x60103a
3
val1:00 dir1:00 evt1:00 val2:00 dir2:00 evt2:00
4
val1:01 dir1:01 evt1:00 val2:02 dir2:00 evt2:01
5
val1:02 dir1:00 evt1:01 val2:04 dir2:00 evt2:02
6
val1:03 dir1:01 evt1:01 val2:06 dir2:00 evt2:03
7
val1:04 dir1:00 evt1:02 val2:09 dir2:01 evt2:04
8
val1:05 dir1:01 evt1:02 val2:0B dir2:01 evt2:05
9
val1:06 dir1:00 evt1:03 val2:0D dir2:01 evt2:06
10
val1:07 dir1:01 evt1:03 val2:0F dir2:01 evt2:07
11
val1:08 dir1:00 evt1:04 val2:10 dir2:00 evt2:08
12
val1:09 dir1:01 evt1:04 val2:12 dir2:00 evt2:09
13
val1:0A dir1:00 evt1:05 val2:14 dir2:00 evt2:0A
14
val1:0B dir1:01 evt1:05 val2:16 dir2:00 evt2:0B
15
val1:0C dir1:00 evt1:06 val2:19 dir2:01 evt2:0C
16
val1:0D dir1:01 evt1:06 val2:1B dir2:01 evt2:0D
17
val1:0E dir1:00 evt1:07 val2:1D dir2:01 evt2:0E
18
val1:0F dir1:01 evt1:07 val2:1F dir2:01 evt2:0F
19
val1:10 dir1:00 evt1:08 val2:20 dir2:00 evt2:10
20
val1:11 dir1:01 evt1:08 val2:22 dir2:00 evt2:11
21
...
22
val1:FD dir1:01 evt1:7E val2:FB dir2:01 evt2:7D
23
val1:FE dir1:00 evt1:7F val2:FD dir2:01 evt2:7E
24
val1:FF dir1:01 evt1:7F val2:FF dir2:01 evt2:7F
25
val1:00 dir1:00 evt1:00 val2:00 dir2:00 evt2:00
26
val1:01 dir1:01 evt1:00 val2:02 dir2:00 evt2:01
27
val1:02 dir1:00 evt1:01 val2:04 dir2:00 evt2:02

Compiler: gcc version 5.4.0 20160609 (Ubuntu 5.4.0-6ubuntu1~16.04.4)

von Wilhelm M. (wimalopaan)


Lesenswert?

Bitfields und unions haben Einschränkungen bzw. Freiheitsgrade, die 
ihren naheliegenden Einsatz manchmal einfach unmöglich machen:

1) Die Anordnung der Bits in einem Bit-Field ist Compiler-abhängig.

http://en.cppreference.com/w/cpp/language/bit_field

Damit scheidet i.A. die ggf. naheliegende Verwendung von ihnen für 
HW-Register oder Serialisierungen aus. Sie eignen sich daher tatsächlich 
nur für abstrakte Bit-Mengen ohne HW-Bezug oder Plattform-Neutralität.

2) Die Verwendung von unions zum "type-punning" in C++ ist UB (in C aber 
ok), denn man darf nur das "active member" verwenden (ist in C++ auch 
logisch, da Elemente einer union eben auch UDT sein können) (es sei 
denn, sie habe eine common-initial-sequence ...)

Dies ist dann bspw. problematisch, wenn man C-Quellen (unbedarft) mit 
einem C++-Compiler verwendet (wobei im C-Code natürlich die 
problematischen Fälle nicht vorkommen können, und in der Praxis für 
fundamentale DT der C++-Compiler wohl so wie der C-Compiler arbeitet, 
aber es ist nicht korrekt, und statische Code-Checker melden das)

von Klaus (Gast)


Lesenswert?

Wilhelm M. schrieb:
> Damit scheidet i.A. die ggf. naheliegende Verwendung von ihnen für
> HW-Register oder Serialisierungen aus. Sie eignen sich daher tatsächlich
> nur für abstrakte Bit-Mengen ohne HW-Bezug oder Plattform-Neutralität.

In den Headerfiles für PICs, die Microchip mit seinen Compilern 
mitliefert, werden alle Registerbits in Bitfeldern angelegt. Die 
Programmierer des XC8 und des XC16 (ist der GCC) sehen das also exakt 
andersherum.

MfG Klaus

von Wilhelm M. (wimalopaan)


Lesenswert?

Klaus schrieb:
> Wilhelm M. schrieb:
>> Damit scheidet i.A. die ggf. naheliegende Verwendung von ihnen für
>> HW-Register oder Serialisierungen aus. Sie eignen sich daher tatsächlich
>> nur für abstrakte Bit-Mengen ohne HW-Bezug oder Plattform-Neutralität.
>
> In den Headerfiles für PICs, die Microchip mit seinen Compilern
> mitliefert, werden alle Registerbits in Bitfeldern angelegt. Die
> Programmierer des XC8 und des XC16 (ist der GCC) sehen das also exakt
> andersherum.

Dann darf man die Headerfiles eben nur zusammen mit dem GCC mit diesem 
ABI verwenden ... das steht wahrscheinlich im Kleingedruckten.

von Rufus Τ. F. (rufus) Benutzerseite


Lesenswert?

Wilhelm M. schrieb:
> Dann darf man die Headerfiles eben nur zusammen mit dem GCC mit diesem
> ABI verwenden

Oder man sollte mal fünf Minuten investieren und den eigenen Compiler 
auf sein Verhalten hin untersuchen.

Ist ja keine Raketenwissenschaft, und dann hat man bis zum nächsten 
Compilerwechsel Gewissheit.

Sind denn, von hypothetischen Beispielen abgesehen, real existierende 
Compiler für eine Prozessorarchitektur bekannt, die Bitfelder 
unterschiedlich anordnen?

Hat schon mal jemand so etwas gesehen oder ist das nur hypothetisches 
"Ich kann aber den Standard lesen"-Getue aus der Informatik-Vorlesung?

von Klaus (Gast)


Lesenswert?

Wilhelm M. schrieb:
> Dann darf man die Headerfiles eben nur zusammen mit dem GCC mit diesem
> ABI verwenden ..

Die Headerfiles für einen PIC machen ja auch nur bei Compiler für einen 
PIC Sinn. Wer würde sie denn für einen anderen Prozessor sinnvoll 
benutzen wollen, da gibts ja ganz andere SFRs. Und wieviele ABIs gibts 
beim GCC für den gleichen Prozessor?

MfG Klaus

von Wilhelm M. (wimalopaan)


Lesenswert?

Klaus schrieb:
> Wilhelm M. schrieb:
>> Dann darf man die Headerfiles eben nur zusammen mit dem GCC mit diesem
>> ABI verwenden ..
>
> Die Headerfiles für einen PIC machen ja auch nur bei Compiler für einen
> PIC Sinn. Wer würde sie denn für einen anderen Prozessor sinnvoll
> benutzen wollen, da gibts ja ganz andere SFRs. Und wieviele ABIs gibts
> beim GCC für den gleichen Prozessor?

Es gibt aber mehr Compiler als die der GCC ...

von Bernd K. (prof7bit)


Lesenswert?

Ein Nachteil mit diesen Bitfeldern ist daß der Adressoperator damit 
nicht funktiouert, man kann keinen Pointer auf so einen Eintrag bekommen 
(was ja auch logisch ist, leider konsequenterweise auch dann nicht wenn 
es ganze 8 Bit sind an einer 8 bit Grenze)

von Bernd K. (prof7bit)


Lesenswert?

Wilhelm M. schrieb:
> Und wieviele ABIs gibts
>> beim GCC für den gleichen Prozessor?

Die Frage muss lauten wie viele ABIs gibts zum Beispiel für ARM Cortex 
(oder irgendeinen anderen Controller) die sich in diesem Punkt 
unterscheiden (oder überhaupt unterscheiden). Das hat erstmal nichts mit 
gcc oder irgendeinem anderen Compiler zu tun.

> Es gibt aber mehr Compiler als die der GCC ...

Das wäre egal wenn sich alle ans ABI der Zielplatform halten. Welche 
Compiler halten sich nicht daran?

von Rolf M. (rmagnus)


Lesenswert?

Bummsfallera schrieb:
> fop schrieb:
>> Aber Vorsicht : die genaue Anordnung im Speicher bleibt Sache des
>> Compilers.
>
> Das möchte ich nochmal hervorheben, weil es unions fast nutzlos macht.

Nutzlos macht es sie nicht. Sie sind aber weder dafür geeignet, noch 
dafür gedacht, um sie für Konvertierungen zu missbrauchen.

Wilhelm M. schrieb:
> Bitfields und unions haben Einschränkungen bzw. Freiheitsgrade, die
> ihren naheliegenden Einsatz manchmal einfach unmöglich machen:

Ich finde diese Art der Nutzung von unions nicht so naheliegend, weil 
irgendwie umständlich. Statt einfach von a nach b zu casten, definiere 
ich mir extra einen eigenen Typ, kopiere die Daten da rein und wieder 
raus und habe damit kunstvoll ein verstecktes Äquivalent eines Casts 
gebastelt.

Rufus Τ. F. schrieb:
> Sind denn, von hypothetischen Beispielen abgesehen, real existierende
> Compiler für eine Prozessorarchitektur bekannt, die Bitfelder
> unterschiedlich anordnen?
>
> Hat schon mal jemand so etwas gesehen oder ist das nur hypothetisches
> "Ich kann aber den Standard lesen"-Getue aus der Informatik-Vorlesung?

Die Frage kann man auch umdrehen:
Kann jemand beweisen, dass alle bisherigen und zukünftigen Compiler 
Bitfelder genau gleich anordnen, oder ist das nur eine naive "ich geh 
einfach davon aus, dass das schon passen wird"-Annahme von 
Möchtegern-Programmieren?
Der Standard ist auch nicht dafür da, damit man ihn einfach ignoriert, 
sondern damit man weiß, worauf man sich verlassen kann und worauf nicht.

von Klaus (Gast)


Lesenswert?

Rufus Τ. F. schrieb:
> Hat schon mal jemand so etwas gesehen oder ist das nur hypothetisches
> "Ich kann aber den Standard lesen"-Getue aus der Informatik-Vorlesung?

Für die Microchip PIC gibts es diese Bitfelder in allen Headerfiles, 
ebenfalls vom Microchip geliefert. Ich gehe mal davon aus, daß die 
meisten wenn nicht alle Großkunden von Microchip diese Bitfelder auch so 
benutzen. ADCON0bits.ADON = 1 ist auch viel lesbarer, als diese Zeilen 
voller << XYZ, bei denen der Compiler noch nicht mal überprüfen kann, ob 
XYZ in diesem Register überhaupt vorkommt. Sollte das in einer neueren 
Version des Compiler mal nicht passend funktionieren, bricht es allen 
alten Code, auch den der professionellen Großkunden. Damit würde sich 
die Fa. Microchip direkt in ein schwarzes Loch katapultieren, sie werden 
also darauf achten, daß das nicht passiert (auch beim XC16 aka GCC).

Ob das mit dem Standard überhaupt stimmt, kann ich nicht beurteilen. Ich 
meine aber gelesen zu haben, daß es in neueren Standards bei Bitfeldern 
eine Präzisierung gegeben hat.

MfG Klaus

von Rufus Τ. F. (rufus) Benutzerseite


Lesenswert?

Rolf M. schrieb:
> Kann jemand beweisen, dass alle bisherigen und zukünftigen Compiler
> Bitfelder genau gleich anordnen,

Das muss man nicht beweisen. Der Unterschied zwischen 
"ich-sitz-hier-in-der-Informatik-Vorlesung" und realer Arbeit ist der, 
daß man sich notfalls fünf Minuten mit seinem neuen Compiler 
beschäftigt, wenn man ihn aus welchen Gründen auch immer gewechselt hat. 
Wer mit einem Compiler ernsthaft arbeitet, kennt ihn, und untersucht 
potentiell kritische Verhaltensweisen.

Wenn die Compiler für eine bestimmte Zielarchitektur sind, dann kann man 
in der Tat davon ausgehen, denn es ist abseits des heiligen Standards 
eine etablierte Arbeitsweise.

Wer Software "beweisen" will, der arbeitet nicht, sondern der geht 
akademischen Spielereien nach.

Oh, und diese Kluft zwischen akademischen Anspruchsdenken und realer 
Arbeitswelt ist auch daran beteiligt, daß auch in diesem Jahrzehnt nach 
wie vor viel mit C89 gearbeitet wird, ohne die tollen neuen Dinge zu 
nutzen, die die verschiedenen neuen Standards mit sich gebracht haben, 
sei es C99 oder C11.

: Bearbeitet durch User
von union jack (Gast)


Lesenswert?

In der normalen Anwendungsentwicklung ist es völlig egal, wie der 
Compiler die Bitfelder intern anlegt und in der hardwarenahen 
Entwicklung ist die Anpassung der Strukturdefinitionen bei einem Wechsel 
des Compilers im laufenden Projekt das geringste Problem (erlebtes 
Beispiel: STM8S). Der Einsatz von 'struct' und 'union' ist in diesem 
Bereich ein sehr elegantes und übersichtliches Stilmittel an dessen 
Einsatz nur Möchtegern-Programmierer scheitern.

von Bernd K. (prof7bit)


Lesenswert?

union jack schrieb:
> In der normalen Anwendungsentwicklung ist es völlig egal, wie der
> Compiler die Bitfelder intern anlegt

Nicht wenn mehrere Softwaren auf unterschiedlichen Platformen auf 
irgendeinem Wege binäre Daten austauschen müssen oder auf irgendein von 
höherer Stelle spezifiziertes Datenformat. Das ist nicht unüblich. In 
dem Falle sollte man sich dreimal und viermal überlegen was man macht 
und wie man es macht.

Notfalls (wenn man wirklich diesen Weg gehen will) kann man das 
beabsichtigte Verhalten (und Abweichungen davon) auch per 
(Compile-Time-)Assert dokumentieren (und eventuelles späteres 
Rätselraten vermeiden), das dokumentiert dann auch daß man zumindest mal 
drüber nachgedacht hat und sich des Sachverhaltes bewußt war.

von Klaus (Gast)


Lesenswert?

Bernd K. schrieb:
> Nicht wenn mehrere Softwaren auf unterschiedlichen Platformen auf
> irgendeinem Wege binäre Daten austauschen

Seit wann tauschen verschiedene Plattformen ihre Hardwareregister?

Wilhelm M. schrieb:
> Damit scheidet i.A. die ggf. naheliegende Verwendung von ihnen für
> HW-Register ...

MfG Klaus

von union jack (Gast)


Lesenswert?

Man kann sich darüber streiten (eigentlich kann man es nicht) ob es 
wirklich die Anwendungsschicht ist die sich über die Bitpositionen von 
Binärdaten kümmern sollte, ich würde das eher etwas tiefer ansetzen. Die 
entsprechenden Überlegungen muss man natürlich immer anstellen, auch bei 
den Alternativen (gerade, wenn zB. 32-bit UDP-Daten verarbeitet werden 
sollen). Ich halte es trotzdem für unerreicht (aus Sicht des 
Quellcodes), zb. einen UDP-Header in eine union schreiben zu können und 
anschliessend über ein struct direkten Zugriff auf alle Felder zu haben. 
Und auch bei den Alternativen muss ich das beabsichtigte Verhalten 
dokumentieren (weil ich mich dort auch auf eine Datenstruktur festlegen 
muss) und der Arbeitsaufwand für spätere Änderungen ist in beiden Fällen 
gegeben. Ich behaupte nicht, das der Weg über structs und unions aus der 
Sicht des Binärcodes der effektivere ist, aber der GCC macht hier einen 
sehr guten Job.

von Bernd K. (prof7bit)


Lesenswert?

Klaus schrieb:
> Seit wann tauschen verschiedene Plattformen ihre Hardwareregister?

Wer hat von Hardwarregistern gesprochen? Es ging um Unions und 
Bitfelder.(wie im Thread-Titel) Meine Antwort bezog sich also auf 
Unions, Structs und Bitfelder.

von Rolf M. (rmagnus)


Lesenswert?

Bernd K. schrieb:
> Klaus schrieb:
>> Seit wann tauschen verschiedene Plattformen ihre Hardwareregister?
>
> Wer hat von Hardwarregistern gesprochen? Es ging um Unions und
> Bitfelder.(wie im Thread-Titel) Meine Antwort bezog sich also auf
> Unions, Structs und Bitfelder.

Der Punkt ist, dass man sie in Programmen intern benutzt, oder bei 
Hardwareregistern (da dort Portabilität eh keine Rolle spielt). Für die 
Kommunikation mehrerer Systeme untereinander sind sie wie schon gesagt 
weder gedacht, noch geeignet. Wenn man sie trotzdem dafür benutzt, muss 
man sich eben selbst um die Probleme kümmern, die daraus entstehen 
können.

von Bernd K. (prof7bit)


Lesenswert?

Rolf M. schrieb:
> Wenn man sie trotzdem dafür benutzt, muss
> man sich eben selbst um die Probleme kümmern, die daraus entstehen
> können.

Man kann um Zeit zu sparen ein paar Asserts an zentraler Stelle 
plazieren die das Compilerverhalten abfragen und damit die auf 
unbestimmte Zukunft (irgendwann oder meistens nie) verschobene Arbeit 
mit einem Alarmsystem auszurüsten das sofort unmißverständlich klingelt 
wenn es nötig wird nochmal Hand anzulegen. Das ist mein Ansatz. Meist 
(99%) wird nichts nötig und die Zeit ist gespart. So frage ich zum 
Beispiel die Größe eines verdächtigen ("wackeligen") Structs mit einem 
Compile-Time Assert ab um in der Zukunft unerwartet geänderte 
Alignment-Regeln sofort zu bemerken. Oder auch die Größe von Enums 
(damit ich sie gefahrlos in structs unterbringen kann).

Bitfelder benutze ich seit geraumer Zeit schon nicht mehr, konnte mich 
eigentlich nie wirklich damit anfreunden, sie wirken auf mich wie ein 
unbedacht hastig drangeflicktes, über-abstraktes aber unterdefiniertes 
und dadurch leider vom Geist der restlichen Sprache und der darunter 
liegenden Maschine entrücktes Feature, ich komme problemlos ohne sie 
aus, ohne daß es unleserlicher oder aufwendiger würde.

: Bearbeitet durch User
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.