Forum: Mikrocontroller und Digitale Elektronik Einzelbits in Byte Namen zuweisen und auswerten


Announcement: there is an English version of this forum on EmbDev.net. Posts you create there will be displayed on Mikrocontroller.net and EmbDev.net.
von Andreas (Gast)


Lesenswert?

Hallo,

wie kann ich in C die 8 Bits eines Bytes mit Namen versehen und diese 
dann gezielt mit dem Namen lesen, setzen, löschen?

uint8_t Status;

Status soll bestehen aus:
Platzhalter0 für bit0
Platzhalter1 für bit1
...
Platzhalter7 für bit7

Damit ich dann das Bit der Übersichtlichkeit mit Status.Platzhalter x 
lesen, setzen, löschen kann?

Beispiele:
Status.Platzhalter1=0; // löscht Bit1 aus Byte Status
if (Status.Platzhalter0==1) { // Wenn Bit0 aus Byte Status = 0 dann...

Lg
Andreas

von Luca E. (derlucae98)


Lesenswert?

Was du suchst, nennt sich bit-field.

https://microchipdeveloper.com/c:bits-bools-and-bit-fields

von Andreas (Gast)


Lesenswert?

Danke, das war genau wonach ich gesucht habe...

von Alexander (alecxs)


Lesenswert?

Mit __ attribute__(( _ packed_)) stehen deine Bits dann auch 
compilerunabhängig ordentlich in Reihe da wo Du die vermutest, falls Du 
mit memcpy auf dein struct zugreifen möchtest.

: Bearbeitet durch User
von Nop (Gast)


Lesenswert?

Aber aufgepaßt: der C-Standard definiert nicht, wie die benannten Bits 
im Byte angeordnet werden. Das taugt also nicht für irgendeine Art von 
externem Datentausch, auch nicht zum Interfacen von Registern, sondern 
rein zur programm-internen Datenverarbeitung. Alles, was extern geht, 
macht man daher über Bitmasken.

Der Hinweis auf "packed" ist falsch, denn der sorgt keineswegs für die 
Anordnung von Bits, sondern dafür, daß bei structs/unions (das ist was 
anderes als Bitfields) keine Pad-Bytes eingefügt werden. 
Compilerunabhängig ist das schon deswegen nicht, weil es kein Teil des 
C-Standards ist.

von Alexander (alecxs)


Lesenswert?

Wieso sind Bitfields kein Struct?
https://gitlab.com/aIecxs/w211-ac-control/-/blob/main/w211_can_b.h#L47

ohne packed funktioniert _das_ nicht... ich hab mir den Wolf gesucht 
bis ich den Fehler gefunden hatte!
https://gitlab.com/aIecxs/w211-ac-control/-/blob/main/pwm_can.ino#L82

Dann war es prozessorunabhängig.
Beitrag "Was packt _attribute_ packed ?"

: Bearbeitet durch User
von Nop (Gast)


Lesenswert?

Alexander schrieb:
> Wieso sind Bitfields kein Struct?

Weil die Anmerkung hier nach der Anordnung der einzelnen Bits war, nicht 
nach eventuellem Padding zwischen den zugrundeliegenden Integern. Die 
Anordnung der benannten Bits innerhalb der Integer ist nicht 
Compiler-unabhängig, auch nicht mit packed.

Deswegen nutzt man Bitfields gerade dort nicht, wo sie verführerisch 
aussehen: Register-Definitionen, Mapping vom Kommunikationsstrukturen / 
Messages auf Bits und dergleichen.

Zu Packed siehe: 
https://gcc.gnu.org/onlinedocs/gcc/Common-Type-Attributes.html#Common-Type-Attributes

von Alexander (alecxs)


Lesenswert?

Nein, meine Anmerkung bezog sich auf das Padding, deswegen auch __ 
attribute__(( _ packed_)). Endianness innerhalb eines "Bytes" hast Du 
Dir selbst dazu gedichtet. Aber danke für den Hinweis.

P.S. In meinem Beispiel findest Du auch Bitfelder mit 3, 12 oder 14 
Bits. Diese lassen sich schlecht in Bytes aufteilen. Deswegen nannte ich 
sie "Bits" konnte schlecht "Bytes" dazu sagen.

: Bearbeitet durch User
von Nop (Gast)


Lesenswert?

Alexander schrieb:
> Endianness innerhalb eines "Bytes" hast Du
> Dir selbst dazu gedichtet.

Ist das so? Du schriebst:

> Mit __ attribute__((  packed)) stehen deine Bits dann auch
> compilerunabhängig ordentlich in Reihe da wo Du die vermutest

Und dem ist eben nicht unbedingt so. Es geht auch nicht um Endianess 
dabei, zumal die bei einem uint8_t wie im Ausgangsposting sowieso keine 
Rolle spielt, sondern der Compiler darf die Bits einsortieren, wie er 
lustig ist. Also bei uint8_t ist 01234567 genauso möglich wie 76543210. 
Genauso erlaubt wäre sogar z.B. 05271634.

Manche Compiler haben Optionen, wie sie Bitfelder sortieren sollen, aber 
das ist eben nicht compiler-unabhängig.

von Alexander (alecxs)


Lesenswert?

Das Padding bestimmt der Compiler. Dann, und nur dann stehen die "Bytes" 
(Bits, Bitfelder, Integer, Bools, whatever) ordentlich in Reihe so dass 
man mit memcpy auch auf die Structs zugreifen kann, wenn das Padding 
eliminiert wurde. Ich kann Dir versichern dass mein Code ohne __ 
attribute__(( _ packed_)) nicht funktioniert hat.

von Nop (Gast)


Lesenswert?

Alexander schrieb:
> Das Padding bestimmt der Compiler. Dann, und nur dann stehen die
> "Bytes" (Bits, Bitfelder, Integer, Bools, whatever) ordentlich in Reihe

Sicher. Nur der Inhalt ist eben in seiner Reihenfolge nicht vom 
C-Standard definiert. Deswegen nutzt man das nicht für Mapping auf 
Register, Messages und dergleichen, wenn man's portabel halten möchte. 
Daß Du mit "packed" eventuelle Lücken eliminiert hast, sagt nichts über 
die Reihenfolge der Bits aus.

von Alexander (alecxs)


Lesenswert?

Deswegen habe ich die Reihenfolge der Bits die mich interessieren 
_vorher_ als Bools im Struct festgelegt. Diese Reihenfolge stimmt sehr 
wohl (mit __ attribute__(( _ packed_))). Warum sollte das nicht 
portabel sein?

von Nop (Gast)


Lesenswert?

Alexander schrieb:
> Deswegen habe ich die Reihenfolge der Bits die mich interessieren
> vorher als Bools im Struct festgelegt.

Eben nicht. Die Reihenfolge, in der Du die Bits innerhalb eines 
Basistyps (hier uint8_t) hinschreibst, haben keinen definierten Bezug 
dazu, wo sie innerhalb des uint8_t dann landen. Siehe: 
Beitrag "Re: Einzelbits in Byte Namen zuweisen und auswerten"

Das verwechselst Du mit structs ohne Bitfields, wo die Reihenfolge der 
Deklaration dann mit der im Speicher übereinstimmt, minus padding (bzw. 
plus packed).

von Nop (Gast)


Lesenswert?

Alexander schrieb:
> Warum sollte das nicht portabel sein?

Ach ja: weil der C-Standard das bei Bitfields nicht definiert.

von W.S. (Gast)


Lesenswert?

Andreas schrieb:
> wie kann ich in C die 8 Bits eines Bytes mit Namen versehen und diese
> dann gezielt mit dem Namen lesen, setzen, löschen?

Im Prinzip garnicht. Es ist bei den meisten Architekturen immer eine 
Folge von:
- Byte laden
- Byte verändern
- Byte zurückschreiben
erforderlich. Zumindest. Kann auch sein, daß es nur 16 Bit-weise oder 
gar 32 Bit-weise geht - je nach Plattform. Eine Ausnahme sind z.B. die 
PIC16, wo man mit einem Maschinenbefehl ein Bit in einem Byte abfragen 
oder verändern kann. Auch die 8051 Architektur sieht so etwas für einige 
Bereiche im RAM vor, aber so etwas hat keinen Eingang in C oder eine 
andere maschinenunabhängige Programmiersprache gefunden. Damit bleibt 
dir immer nur die Abfolge Laden/Verändern/Speichern des gesamten Bytes 
übrig. Ganz egal, ob du das nun in irgend eine Verpackung tust oder 
nicht. Für gewöhnliche Bytes im RAM geht das ja, aber bei Registern in 
der Peripherie geht das oftmals nicht so, genaueres siehe Manual zum 
Chip.

W.S.

von Nop (Gast)


Lesenswert?

W.S. schrieb:

> Es ist bei den meisten Architekturen immer eine Folge von:
> - Byte laden
> - Byte verändern
> - Byte zurückschreiben
> erforderlich.

Was auf solchen Architekturen übrigens den Nebeneffekt hat, daß selbst 
eine Zuweisung eines Bits nicht-atomar ist, was bei Betrachten des 
Quelltextes aber nicht gleich auffällt, wenn das eine Zuweisung an ein 
Bitfield ist.

von Alexander (alecxs)


Lesenswert?

Nop schrieb:
> Das verwechselst Du mit structs ohne Bitfields, wo die Reihenfolge der
> Deklaration dann mit der im Speicher übereinstimmt, minus padding (bzw.
> plus packed).

Ich verwechsele hier gar nichts. Du redest von der Endianness eines 
uint8_t. Ich rede von einem Bitfield Struct mit Booleans.

Wenn Dir die Endianness nicht vorher bekannt ist, dann musst Du es halt 
doppelt definieren (Habe ich nie gebraucht):
1
typedef struct Status_t {
2
  #if __BYTE_ORDER == __LITTLE_ENDIAN
3
    bool Platzhalter0 : 1;
4
    bool Platzhalter1 : 1;
5
    bool Platzhalter2 : 1;
6
    bool Platzhalter3 : 1;
7
    bool Platzhalter4 : 1;
8
    bool Platzhalter5 : 1;
9
    bool Platzhalter6 : 1;
10
    bool Platzhalter7 : 1;
11
  #elif __BYTE_ORDER == __BIG_ENDIAN
12
    bool Platzhalter7 : 1;
13
    bool Platzhalter6 : 1;
14
    bool Platzhalter5 : 1;
15
    bool Platzhalter4 : 1;
16
    bool Platzhalter3 : 1;
17
    bool Platzhalter2 : 1;
18
    bool Platzhalter1 : 1;
19
    bool Platzhalter0 : 1;
20
  #endif
21
} __attribute__((__packed__)) Status_t;

Willst Du mir jetzt sagen GNU ist kein Standard? Mit welchem Compiler 
arbeitest Du? Funktioniert der Code bei Dir nicht?

: Bearbeitet durch User
von Nop (Gast)


Lesenswert?

Alexander schrieb:

> Du redest von der Endianness eines uint8_t.

Nein, rede ich nicht, zumal ein uint8_t auch keine Endianess hat. 
Endianess ist was völlig anderes, wie ich bereits mehrfach erwähnt habe.

Ich rede davon, daß das erste Bit in Deinem Bitfeld auf einem uint8_t 
nicht auf Bit 0 des uint8_t liegen muß, und auch nicht auf Bit 7, 
sondern auf irgendeinem Bit liegen kann. Das steht dem verwendeten 
Compiler völlig frei (und hat mit Plattform-Endianess nichts zu tun), 
auch wenn in der Praxis von unten oder von oben her aufgefüllt wird.

> Willst Du mir jetzt sagen GNU gcc ist kein Standard?

Standard ist allein der C-Standard, sonst gar nichts, und der sagt dazu 
halt nichts.

> Funktioniert der Code bei Dir nicht?

Nicht portabel != funktioniert nicht. Völlig anderes Problem.

von Alexander (alecxs)


Lesenswert?

Nop schrieb:
> Ich rede davon, daß das erste Bit in Deinem Bitfeld auf einem uint8_t
> nicht auf Bit 0 des uint8_t liegen muß, und auch nicht auf Bit 7,
> sondern auf irgendeinem Bit liegen kann.

Nennen wir es Bit-endianness. Praktisches Beispiel bitte. Reden wir hier 
noch von Mikrocontrollern?

: Bearbeitet durch User
von Nop (Gast)


Lesenswert?

Alexander schrieb:

> Praktisches Beispiel bitte.

Es ist im C-Standard nicht definiert, wie die Reihenfolge ist, folglich 
Compiler-spezifisch, folglich nicht portabel. Es kann sich also nicht 
nur von Compiler zu Compiler, sondern auch mit einem Compiler-Update 
ändern. Das ist elementare Logik und nichts, was ein "Beispiel" 
bräuchte.

Kannst Dir ja ansonsten mal die Kommentare bei 
https://embeddedgurus.com/stack-overflow/2009/10/effective-c-tip-6-creating-a-flags-variable/#comments 
ansehen, wo Leute schon mit sowas reingefallen sind. Oder halt auf SO: 
https://stackoverflow.com/questions/55823879/should-i-use-bit-fields-for-mapping-incoming-serial-data

von Nop (Gast)


Lesenswert?

Achso, und "Bit-Endianess" ist es auch nicht, weil es mit der CPU 
nichts, aber auch gar nichts zu tun hat. Es liegt einzig am Compiler, 
wie er Bitfields implementiert.

von Wilhelm M. (wimalopaan)


Lesenswert?

Einfach mal hier schauen:

https://en.cppreference.com/w/c/language/bit_field

(unter Notes).

Daher für bspw. explizites Bit-Placement unbrauchbar bei etwa 
µC-Registern.

Das heißt aber nicht, dass es nicht zufälligerweise funktionieren kann. 
Ist aber eben IB und damit eben ein moving-target ;-)

Hinzu kommt wie oben schon gesagt wurde, dass meistens das als RMW 
(nicht atomar) umgesetzt werden (muss), sofern der µC dafür keine 
Unterstützung mitbringt (bit-set-Befehle wie etwa AVR SBI/CBI oder 
set-reset-register)

von Anselm (Gast)


Lesenswert?

Meine Lösung ist folgende:
in der .h:
1
#define SETBIT(REG, PIN) ((REG) |= (uint32_t) 1 << (PIN))
2
#define CLEARBIT(REG, PIN) ((REG) &= ~((uint32_t) 1 << (PIN)))
3
#define CHANGEBIT(REG, PIN, WERT) ((WERT) ? SETBIT((REG), (PIN)) : CLEARBIT((REG), (PIN)))
4
#define READBIT(REG, PIN) (((REG) >> (PIN)) & 1)
5
6
// und die Bits definieren mit:
7
// LEDBYTE (Byte)
8
#define FAULT_LED             3
9
#define OPERATION_LED          6
10
#define NETWORK_LED            5
11
#define HEATER_LED            4
// aufrufen in C dann mit
1
READBIT(LEDBYTE, HEATER_LED)

von Klaus H. (klummel69)


Lesenswert?

Ich würde alle Zugriffe eher in (Inline)Funktionen kapseln.
Dann kann man den nichtatomaren
Aufruf gleich noch mit einbauen.
1
GetData1(structx)
2
SetData1(structx, data)
3
IsBusy(structx)
4
//Usw

Falls mann doch auf alle guten Ratschläge pfeift und die Bit Position 
wichtig ist:

In jeder Übersetzungseinheiten per static_assert die structx Architektur 
checken.
So habe ich es früher gemacht und tatsächlich bei einem Compilerwechsel 
den gefährlichen Zustand entdeckt.

von Alexander (alecxs)


Lesenswert?

Na dann viel Spaß mit den Bitmasken im C Standard. Ich weise darauf hin 
meine .h ist autogeneriert ;) für den Arduino reichts

von foobar (Gast)


Lesenswert?

> typedef struct Status_t {
>     bool Platzhalter0 : 1;
>     ...
> } __attribute__((_packed_)) Status_t;

Hier liegt das Problem doch beim "bool".  Dessen Größe ist 
implementation-defined (und hat sich beim GCC im Laufe der Zeit auch 
verändert).  Wenn der z.B. als "typedef { false, true } bool;" definiert 
ist, liefert "sizeof Status_t" ohne packed 4, mit packed 1.  Wo die 
Bits dabei landen, weiß der Deibel.

von Alexander (alecxs)


Lesenswert?

Wo sollen die landen bei "mit packed 1" ;)

von Wilhelm M. (wimalopaan)


Lesenswert?

foobar schrieb:
> Hier liegt das Problem doch beim "bool".

Ist seit C99 explizit zugelassen neben den drei anderen DT unsigned, 
signed und int.

von W.S. (Gast)


Lesenswert?

Alexander schrieb:
> Wo sollen die landen bei "mit packed 1" ;)

Mal ne ernste Frage: Wozu soll dieser Diskurs gut sein?

Ist es nur zwecks Besserwisserei oder steckt ein ernstes Anliegen 
dahinter? In letzterem Falle wäre die Frage, ob es irgendwelche 
Innereien eines Lowlevel-Treibers betreffen sollen oder ob es Signale 
wie "Lampe_Ein" oder "Schotten_dicht" sein sollen, die in irgendwelchen 
Algorithmen verwendet werden sollen. Sind es Treiber-Innereien, dann ist 
das Arbeiten mit #define Einschaltbit (1<<7) oder so angesagt. Sind es 
Signale wie genannt, dann ist angesagt, sowas in einzelne Funktionen zu 
verpacken (a la void Lampe_Ein(void) oder so) und in eine separate 
Quelle zu verfrachten. Dann ist die Firmware auch mit geringem Aufwand 
portabel.

Und daß das Herumhampeln mit Bitfeldern eine heikle Sache ist, wurde dir 
ja bereits gesagt.

W.S.

von Alexander (alecxs)


Lesenswert?

Warum sprichst du mich an? Ich habe nur einen Tipp gegeben.

Die Besserwisserei (geht's nicht immer darum?) dass die von mir 
bevorzugte Lösung hypothetisch auf irgendeinem Mikrocontroller mal nicht 
funktionieren könnte, weil nicht portabel kein C Standard, nicht 
definiert, kein GNU compiler benutzt, bla bla habe nicht ich 
losgetreten.

von Wilhelm M. (wimalopaan)


Lesenswert?

Alexander schrieb:
> Na dann viel Spaß mit den Bitmasken im C Standard. Ich weise darauf hin
> meine .h ist autogeneriert ;)

Von wem?

von Alexander (alecxs)


Lesenswert?

Ist doch alles auf gitlab. das  211_219_I_AEJ2003_X.dat file wird 
ausgelesen und die Structs generiert. Ein Fahrzeug hat über 50 
Steuergeräte. Jede CAN ID hat eine eigene Bitstruktur und daher sein 
eigenes Struct. Der Aufbau ist immer gleich, daher problemlos via script 
generierbar. Ich hab nur 3 CAN IDs gebraucht, und selbst das wäre mir zu 
viel gewesen.

eingelesen wird mit
1
memcpy(&struct, msg, len);

Mir konnte immer noch keiner sagen auf welchem Mikrocontroller das nicht 
funktionieren soll. Da hab ich ja richtig Glück gehabt dass es auf 
meinem Intel und auf dem Kinetis läuft ;)

von Nop (Gast)


Lesenswert?

Alexander schrieb:
> Da hab ich ja richtig Glück gehabt dass es auf
> meinem Intel und auf dem Kinetis läuft ;)

Wenn Du bis jetzt nicht verstanden hast, was das Problem von 
nicht-portablem Code ist, dann wirst Du es auch nicht mehr verstehen. 
Ist halt mehr was für Profis.

von Alexander (alecxs)


Lesenswert?

Ich bin kein Programmierer und habe keine Anforderungen an MISRA. Und 
Profi bin ich erst Recht nicht, ich habe noch nie was selbst 
programmiert. Es macht keinen Sinn die Kontroverse aus Deinen Links hier 
fortzuführen, wenn schon die Profis sich uneinig sind.

von Wilhelm M. (wimalopaan)


Lesenswert?

Alexander schrieb:
> Ich bin kein Programmierer und habe keine Anforderungen an MISRA. Und
> Profi bin ich erst Recht nicht, ich habe noch nie was selbst
> programmiert.

Das sieht man. Allerdings machst Du dafür eine große Welle ...

> Es macht keinen Sinn die Kontroverse aus Deinen Links hier
> fortzuführen, wenn schon die Profis sich uneinig sind.

Die Profis sind sich einig: Bit-Fields für Compiler/Architektur 
übergreifenden Zugriff oder Zugriff auf µC-Register sind nicht-portabel, 
weil IB. Man kann Glück haben - wie Du offensichtlich - doch es bleibt 
wackelig (sofern Du das nicht durch Zusicherungen absicherst. Da Du aber 
kein Programmierer bist, weißt Du auch nicht das Zusicherungen sind. 
Auch wieder blöd ...)

von Alexander (alecxs)


Lesenswert?

Wir sind hier aber auch im Unterforum Mikrocontroller und Elektronik, 
wäre nicht verkehrt anzunehmen es ginge um praktikable Ansätze im 
Hobbybereich :)

: Bearbeitet durch User
von Wilhelm M. (wimalopaan)


Lesenswert?

Alexander schrieb:
> Wir sind hier aber auch im Unterforum Mikrocontroller und Elektronik,
> wäre nicht verkehrt anzunehmen es ginge um praktikable Ansätze im
> Hobbybereich :)

Die praktikablen Ansätze wurden alle schon genannt.

von Alexander (alecxs)


Lesenswert?


von Wilhelm M. (wimalopaan)


Lesenswert?

Alexander schrieb:
> Ja, und ich finde eben den hier ganz praktikabel:
> Nop schrieb:
>>
> 
https://embeddedgurus.com/stack-overflow/2009/10/effective-c-tip-6-creating-a-flags-variable

Sicher.

Du schickst etwas von diesen Bits von einem µC zu einem anderen µC?
Du benutzt dies um auf Register eines µC oder Peripherie zu zu greifen?

Wie beantwortest Du dieses Fragen?

von Alexander (alecxs)


Lesenswert?

Wenn Du Steuergeräte im Auto als µC bezeichnen willst, mit Ja (1)

Für die zweite Frage wäre es gut mal einen realen Fall aus der Praxis zu 
zeigen, wo das ein tatsächliches Problem ist.

(Link reicht)

: Bearbeitet durch User
von Wilhelm M. (wimalopaan)


Lesenswert?

Alexander schrieb:
> Wenn Du Steuergeräte im Auto als µC bezeichnen willst, mit Ja (1)

Bingo. Dann funktioniert der Datenaustausch eben nur mit viel Glück.

> Für die zweite Frage wäre es gut mal einen realen Fall aus der Praxis zu
> zeigen, wo das ein tatsächlich ein Problem ist.

Hast Du das immer noch nicht verstanden?

Im Register des µC ist Bit0 für den Reset einer internen Peripherie 
zuständig, und Bit1 ist ein Status-Bit.

Du hast zwar in dem Bit-Field die Bits nun von 0 bis 7 angeordnet, der 
Compiler platziert aber das Element 0 nicht bei Bit0 sondern irgendwo 
anders. Dann geht Dein vermeintlicher Reset der Peripherie ggf. nicht, 
weil Du irgendein anderes Bit (evtl. das o.g. Status-Bit) erwischt. Und 
mit der nä. Compiler-Version ist es wieder anders.

von Alexander (alecxs)


Lesenswert?

Wilhelm M. schrieb:
> der Compiler platziert aber das Element 0 nicht bei Bit0 sondern
> irgendwo anders.
> [...] Und mit der nä. Compiler-Version ist es wieder anders.

Was gibt's daran nicht zu verstehen? Ich habe aber nach einem realen 
Fall gefragt, wo einen das "Glück" verlässt. Welcher µC, welcher 
Compiler (beachte: __ attribute__(( _ packed_)) = GNU Extension)??

von Wilhelm M. (wimalopaan)


Lesenswert?

Alexander schrieb:
> Wilhelm M. schrieb:
>> der Compiler platziert aber das Element 0 nicht bei Bit0 sondern
>> irgendwo anders.
>> [...] Und mit der nä. Compiler-Version ist es wieder anders.
>
> Was gibt's daran nicht zu verstehen?

Keine Ahnung ;-)

> Ich habe aber nach einem realen
> Fall gefragt, wo einen das "Glück" verlässt. Welcher µC, welcher
> Compiler (beachte: __ attribute__(( _ packed_)) = GNU Extension)??

Die Syntax _attribute_ ist GNU spezifisch. Du kannst aber mit C23 die 
genormte Syntax verwenden:
1
[[ attr ]]
 Damit bleibt es aber immer noch IB.

Außerdem hat "packed" NICHTS mit der Anordnung der Bits zu tun, das hast 
Du immer noch nicht verstanden. Dazu hatte ich oben einen Link auf den 
Standard gepostet wo das drin steht.

: Bearbeitet durch User
von Alexander (alecxs)


Lesenswert?

Wilhelm M. schrieb:
> Außerdem hat "packed" NICHTS mit der Anordnung der Bits zu tun

Es korreliert aber! Und mir hat noch keiner den schwarzen Schwan 
gebracht.

Im übrigen habe ich "Bytes" als "Bits" - im Sinne von Bitgruppe - 
bezeichnet. Gemeint war, dass die Struct Member nur gepackt am richtigen 
Offset zu finden sind. Und diese können aus nur 1 Bit bestehen. Das 
ursprüngliche Post #4 war flapsige Umgangssprache und Nop hat das 
erstmal korrigiert/thematisiert. Über die Anordnung der EINZELNEN Bits 
INNERHALB eines Boolean (oder uint8_t Platzhalter0:1;) habe ich mir 
vorher keine Gedanken gemacht... das hat "zufällig" über die Byte 
Endianness funktioniert.

Alexander schrieb:
> Wo sollen die landen bei "mit packed 1" ;)

: Bearbeitet durch User
von Wilhelm M. (wimalopaan)


Lesenswert?

Alexander schrieb:
> Wilhelm M. schrieb:
>> Außerdem hat "packed" NICHTS mit der Anordnung der Bits zu tun
>
> Es korreliert aber!

Jein. Natürlich hat das padding Einfluss. Aber davon sprechen wir hier 
gar nicht, sondern einzig allein über die Bit-Anordnung im 
underlying-type.
Aus der Bemerkung ziehe ich den Schluss, dass Du es immer noch nicht 
verstanden hast, den Unterschied zwischen padding und Bit-Anordnung.

> Im übrigen habe ich "Bytes" als "Bits" - im Sinne von Bitgruppe -
> bezeichnet. Gemeint war, dass die Struct Member nur gepackt am richtigen
> Offset zu finden sind. Und diese können aus nur 1 Bit bestehen. Das
> ursprüngliche Post #4 war flapsige Umgangssprache und Nop hat das
> erstmal korrigiert/thematisiert. Über die Anordnung der EINZELNEN Bits
> INNERHALB eines Boolean (oder uint8_t Platzhalter0:1;) habe ich mir
> vorher keine Gedanken gemacht... das hat "zufällig" über die Byte
> Endianness funktioniert.

Im übrigen ist uint8_t strenggenommen auch nicht zulässig als 
underlying-type, sondern nur int, signed, unsigend und bool (s.a. 
C-Standard).

von Peter D. (peda)


Lesenswert?

Man kann das Ganze ungeheuer kompliziert betrachten.
Man kann aber auch einfach auf avr-gcc testen und dann die gültige 
Bitorder anwenden:
1
To determine the compiler is avr-gcc, you need to test for 2 macros __GNUC__ and __AVR__

Die avr-gcc Entwickler sind recht konservativ, sie werden niemals die 
ungünstige Vorbelegung von R0, R1 ändern. Daher werden sie erst recht 
nicht die Bitorder ändern.

von Wilhelm M. (wimalopaan)


Lesenswert?

Peter D. schrieb:
> Man kann das Ganze ungeheuer kompliziert betrachten.
> Man kann aber auch einfach auf avr-gcc testen und dann die gültige
> Bitorder anwenden:
>
1
> To determine the compiler is avr-gcc, you need to test for 2 macros 
2
> __GNUC__ and __AVR__
3
>

Das Thema static_assert o.ä. wurde doch auch schon längst genannt.

Das mit AVR hilft ihm aber auch nicht wirklich, weil er ja Intel und ARM 
kommunizieren lässt ;-)

: Bearbeitet durch User
von Alexander (alecxs)


Lesenswert?

Ich habe verstanden dass mein Workaround keine portable Problemlösung im 
C Standard ist. Danke für den Hinweis

von Klaus H. (klummel69)


Lesenswert?

Nicht aus Provokation sondern aus Interesse und Spieltrieb:

Kennt jemand eine konkrete Compilerversion, die die Bitfields 
Reihenfolge verändert?

: Bearbeitet durch User
Beitrag #7214101 wurde vom Autor gelöscht.
von Wilhelm M. (wimalopaan)


Lesenswert?

Klaus H. schrieb:
> Nicht aus Provokation sondern aus Interesse und Spieltrieb:
>
> Kennt jemand eine konkrete Compilerversion, die die Bitfields
> Reihenfolge verändert?

Bei ARM64 ist es konfigurierbar/veränderbar:

https://github.com/ARM-software/abi-aa/blob/60a8eb8c55e999d74dac5e368fc9d7e36e38dda4/aapcs64/aapcs64.rst#8182bit-field-extraction-expressions

Der Compiler ist demgegenüber agnostisch und das ABI kann umschalten ;-)

: Bearbeitet durch User
von Klaus H. (klummel69)


Lesenswert?

Danke.

Hast du auch ein Beispiel in dem aus Optimierungszwecken die 
Bitreihenfolge sich ändert?

von Wilhelm M. (wimalopaan)


Lesenswert?

Klaus H. schrieb:
> Danke.
>
> Hast du auch ein Beispiel in dem aus Optimierungszwecken die
> Bitreihenfolge sich ändert?

Beispiel wegen Optimierung, also durch bspw. Umschalten von -O0 auf -O3 
?: mir ist kein Beispiel bekannt.

von Ralf G. (ralg)


Lesenswert?

Klaus H. schrieb:
> Hast du auch ein Beispiel in dem aus Optimierungszwecken die
> Bitreihenfolge sich ändert?

Ich häng' mich als Laie mal rein.
Ich könnte mir vorstellen, dass Bitmanipulationen, die man günstig mit 
speziellen Befehlen für Halbbytes macht, eine solche Neuanordnung zur 
Folge haben.

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.