Forum: Mikrocontroller und Digitale Elektronik Byte bitweise und als ganzes zugreifen als Datentyp in c


von Martin S. (mmaddin)


Lesenswert?

Hallo zusammen,

ich möchte auf ein Byte bitweise und auch als ganzes zugreifen.

typedef struct led1bits
{
  uint8_t led1 :1,
          led2 :1,
          led3 :1,
          led4 :1,
          led5 :1,
          led6 :1,
          led7 :1,
          led8 :1;
};

led1bits leds;

Aber wie bekomme ich das ganze in eine union, sodass ich auch leds.byte 
schreiben kann? Es war ganz einfach, oder kann ich das Bitfeld auch 
direkt in der union amlegebn? wenn ja, wie geht das noch, sodass ich es 
als Datentyp wie ein int einsetzen kann?

Es ist zu lang her...

Danke

von Rahul D. (rahul)


Lesenswert?

Martin S. schrieb:
> typedef struct led1bits
> {
>   uint8_t led1 :1,
>           led2 :1,
>           led3 :1,
>           led4 :1,
>           led5 :1,
>           led6 :1,
>           led7 :1,
>           led8 :1;
> };
1
typedef union led1union
2
{
3
 struct led1bits;
4
 uint8_t led1byte
5
};

: Bearbeitet durch User
von Johann L. (gjlayde) Benutzerseite


Lesenswert?

Martin S. schrieb:
> Aber wie bekomme ich das ganze in eine union, sodass ich auch
> leds.byte schreiben kann?

Das geht im einer GNU-C Erweiterung, "anonymous Struct" oder wie das 
heißt:
1
typedef union
2
{
3
    struct
4
    {
5
       uint8_t bit0 :1;
6
       uint8_t bit1 :1;
7
       uint8_t bit2 :1;
8
       uint8_t bit3 :1;
9
       uint8_t bit4 :1;
10
       uint8_t bit5 :1;
11
       uint8_t bit6 :1;
12
       uint8_t bit7 :1;
13
    };
14
    uint8_t byte;
15
} led_t

Damit geht der Zugriff dann so:
1
    led_t led;
2
    led.byte = 0x42;
3
    led.bit2 = 1;
Mit Standard-C muss die Struct benamt sein, also
1
typedef union
2
{
3
    struct
4
    {
5
       ...
6
    } bits;
7
    uint8_t byte;
8
} led_t
mit Zugriff:
1
    led.byte = 0x42;
2
    led.bits.bit2 = 1;

von Martin S. (mmaddin)


Lesenswert?

Johann L. schrieb:
> Das geht im einer GNU-C Erweiterung,

Genau das habe ich gesucht, wollte mir alle "Zwischenamen" sparen, 
wusste aber nicht mehr, wie ich das ideal verschachteln kann, klasse, 
läuft schon, vielen Dank.

Ich mache das mit dem struct allerdings so:
struct
{
  uint8_t led1 :1,
          led2 :1,
          led3 :1,
          led4 :1,
          led5 :1,
          led6 :1,
          led7 :1,
          led8 :1;
};

 Wird das:

    struct
    {
       uint8_t bit0 :1;
       uint8_t bit1 :1;
       uint8_t bit2 :1;
       uint8_t bit3 :1;
       uint8_t bit4 :1;
       uint8_t bit5 :1;
       uint8_t bit6 :1;
       uint8_t bit7 :1;
    };

nachher wirklich ein byte?

würde dann ja auch so gehen:

    struct
    {
       bool bit0 :1;
       bool bit1 :1;
       bool bit2 :1;
       bool bit3 :1;
       bool bit4 :1;
       bool bit5 :1;
       bool bit6 :1;
       bool bit7 :1;
    };

: Bearbeitet durch User
von Rahul D. (rahul)


Lesenswert?

Martin S. schrieb:
> nachher wirklich ein byte?

Teste es mit "sizeof"!

Martin S. schrieb:
> struct
>     {
>        bool bit0 :1;
>        bool bit1 :1;
>        bool bit2 :1;
>        bool bit3 :1;
>        bool bit4 :1;
>        bool bit5 :1;
>        bool bit6 :1;
>        bool bit7 :1;
>     };

Bool ist doch ein int und das ist 16Bit breit.

von Nemopuk (nemopuk)


Lesenswert?

Rahul D. schrieb:
> Bool ist doch ein int und das ist 16Bit breit.

Mindestens bei AVR, ARM Cortex-M und gcc für Linux sind 8 Bit schon 
richtig. Bool ist ein unsigned char, nicht int.

: Bearbeitet durch User
von Christian M. (christian_m280)


Lesenswert?

Warum tut Ihr Euch das an? Findet Ihr das geil, solche Konstrukte, nur 
um ein Bit zu adressieren? Dass man sowas überhaupt fragen muss, 
unglaublich! Nur weil Euer lustiges C "Standard" ist...

Bit-Adressierung in mikroBasic:
1
PORTB.5 = 0

Und in Oshonsoft-Basic:
1
TRISA.1 = 0

Low-Byte und High-Byte:
1
i = x.LB
2
j = x.HW

Während Ihr Euch mit der Syntax abmüht, kann man sich in anderen 
Programmiersprachen auf die Aufgabe konzentrieren!

Gruss Chregu

von Rahul D. (rahul)


Lesenswert?

Christian M. schrieb:
> Während Ihr Euch mit der Syntax abmüht, kann man sich in anderen
> Programmiersprachen auf die Aufgabe konzentrieren!

"Kein ernsthafter Programmierer über 12 Jahre arbeitet mit Basic." - 
Spruch eines Profs aus dem Studium.
Basic ist was für alte Leute, die das vor zig Jahren mal gelernt haben 
(in der DDR war es wohl noch ziemlich verbreitet) oder was zum Einstieg.
Statt Basic nimmt man inzwischen doch eher python.

Christian M. schrieb:
> Oshonsoft-Basic:
Teuer...
> mikroBasic:
gleiches Problem.


gcc? Kost nix außer Hirnschmalz.

Außerdem ist C bei Mikrocontrollern wohl verbreiter als Basis.

von Nemopuk (nemopuk)


Lesenswert?

Christian M. schrieb:
> Findet Ihr das geil, solche Konstrukte,

Es geht nicht darum, was wir geil finden. Wir können uns die 
Programmiersprache nicht einfach frei aussuchen.

Nur weil Microbasic hier und da eleganter ist, kann es noch lange nicht 
C ersetzen. Das closed-source Modell ist für viele Firmen schon ein 
Blocker. Dazu kommen zahlreiche bewährte Bibliotheken, die man nicht 
ohne wichtigen Grund neu schreibt. Die performance wäre auch noch ein 
Punkt.

: Bearbeitet durch User
von Joachim B. (jar)


Lesenswert?

Rahul D. schrieb:
> "Kein ernsthafter Programmierer über 12 Jahre arbeitet mit Basic." -
> Spruch eines Profs aus dem Studium.

komisch in meinem E-Technik Studium zum Diplomingenieur war Basic am 
Terminal vom Großrechner Standard. Wir waren ALLE über 12 Jahre.
OK, ernsthaft programmieren wollten die meisten wohl nicht machen 
deswegen ja E-Technik und nicht Informatik.

: Bearbeitet durch User
von Gunnar F. (gufi36)


Lesenswert?

Joachim B. schrieb:
> komisch in meinem E-Technik Studium zum Diplomingenieur war Basic am
> Terminal vom Großrechner Standard.

Wann? Ich durfte Assembler auf 8086 am Großrechner-Terminal lernen. War 
Anno 1986.

von Rahul D. (rahul)


Lesenswert?

Joachim B. schrieb:
> komisch in meinem E-Technik Studium zum Diplomingenieur war Basic am
> Terminal vom Großrechner Standard.
Vermutlich weil die Konstrukteure des Großrechners das so wollten.
Großrechner != Mikrocontroller

> Wir waren ALLE über 12 Jahre.
Ja, und zu dem Spruch sollte man sich noch das Grinsen des Profs denken.
Im Bildverarbeitungslabor haben wir mit VisualBasic programmiert.
Einerseits gab es das damals (Anfang der 2000er) schon kostenlos von MS, 
andererseits hatten wir eine großen Anteil Kommilitonen, die gerade mal 
ihren PC zum Schreiben der Hausaufgaben einschalten konnten.

> OK, ernsthaft programmieren wollten die meisten wohl machen deswegen ja
> E-Technik und nicht Informatik.
Informatik hat eigentlich nur zweitrangig was mit der Verwendung von 
Programmiersprachen zu tun. Das ist (an der Uni) ziemlich theoretischer 
Kram, weswegen viele lieber an die FH gegangen sind (andere haben eine 
Ausbildung angefangen...).

von Gunnar F. (gufi36)


Lesenswert?

Rahul D. schrieb:
> andere haben eine Ausbildung angefangen...

Das würde mich mal aus der Praxis interessieren: Der Beruf des 
Fachinformatiker für Anwendungsentwicklung: Wie viele davon entwickeln 
tatsächlich Anwendungen?

In meinem Berufsleben habe ich überwiegend Elektroingenieure kennen 
gelernt, die als Quereinsteiger programmieren.

von Joachim B. (jar)


Lesenswert?

Rahul D. schrieb:
> Informatik hat eigentlich nur zweitrangig was mit der Verwendung von
> Programmiersprachen zu tun.

und trotzdem hatten wir in der Industrie eine studentische Hilfskraft 
die "unseren Ing. Code" sauber in Libs umsetzte damit sie für alle 
nutzbar wurde, stellenweise sogar in ASM weil der Prüfrechner PC zu 
wenig Speicher hatte.

Gunnar F. schrieb:
> In meinem Berufsleben habe ich überwiegend Elektroingenieure kennen
> gelernt, die als Quereinsteiger programmieren.

wie alle bei "uns" in der Prüfmittelentwicklung.

Der Abteilungsleiter war sogar verwundert warum unser Werkstudent die 
größte teuerste Maschine ein 486er mit 19" Monitor für 25.000,- DM bekam 
und nicht der Projekt führende Ingenieur. Wir mustem dem 
Abteilungsleiter erklären das alle Prüfingnieure davon provitieren wenn 
die studentische Hilfskraft mehr Compilerläufe pro Tag schafft, während 
wir auf dem blinkenden Cursor schauend über den nächsten Programmteil 
nachdachten, top down Entwicklung.

von Norbert (der_norbert)


Lesenswert?

Ich finde es erstaunlich, dass man überhaupt auf einen solch dummen 
Kommentar eingeht.

Die korrekte Vorgehensweise wäre bei der bloßen Erwähnung von
>  … Basic …

Ein Folgeeintrag als Antwort (Ein einziger!):

* Im Titel steht ›C‹
* Im Eröffnungsbeitrag steht ›C‹
* Die Frage bezieht sich auf ›C‹

von Rahul D. (rahul)


Lesenswert?

Norbert schrieb:
> Ein Folgeeintrag als Antwort (Ein einziger!):
>
> * Im Titel steht ›C‹
> * Im Eröffnungsbeitrag steht ›C‹
> * Die Frage bezieht sich auf ›C‹

Da das Ursprungsthema abgehandelt ist, kann man auch wieder etwas 
offtopic werden...

von Johannes (zuberjo)


Lesenswert?

Basic spielt heute im E-Technik Studium keine Rolle mehr. C, C++, Java, 
C# und geringfügig Assembler. Zusätzlich noch ein wenig VHDL und mehr 
brauchts auch nicht im Berufsleben als E-Techniker. Und wenn doch, dann 
kann man es auch da noch lernen. Die Alten sehen das vllt anders.

Das mit dem Struct, union und Zuweisung mit Doppelpunkt ist jedenfalls 
sehr interessant und werde ich bei mir in C Projekten definitiv mal 
anwenden. Bisher hatte ich mir enumerationen erstellt und einzelne Bits 
über Bitoperatoren verändert.

uint8_t var
enum{
  Bit0 = 1,
  Bit1 = 2
}
Bit setzen: var |= (1<<Bit0)
Bit löschen dann var &= ~(1<<Bit0)

Ist auch ok und funktioniert halt auch genau so in C#. Werde jetzt kein 
Projekt umschreiben, aber bei einem neuen das mit den Struct mal 
ausprobieren

von Norbert (der_norbert)


Lesenswert?

Johannes schrieb:
> Ist auch ok und funktioniert halt auch genau so in C#. Werde jetzt kein
> Projekt umschreiben, aber bei einem neuen das mit den Struct mal
> ausprobieren

Wenn man sich jetzt noch daran erinnert, dass man aus einer Union immer 
nur das ausliest, was man zuvor hinein geschrieben hat, dann ist alles 
prima.
* uint8_t ──▶ uint8_t
* bits ──▶ bits

Nicht aber:
* uint8_t ──▶ bits
* bits ──▶ uint8_t

von Nemopuk (nemopuk)


Lesenswert?

Norbert schrieb:
> Nicht aber ...

Wetten, genau das war aber die Intention dahinter?

von Rahul D. (rahul)


Lesenswert?

Norbert schrieb:
> Nicht aber:
> * uint8_t ──▶ bits
> * bits ──▶ uint8_t

Warum nicht?
Warum funktioniert das bei mir?

von Norbert (der_norbert)


Lesenswert?

Nemopuk schrieb:
> Norbert schrieb:
>> Nicht aber ...
>
> Wetten, genau das war aber die Intention dahinter?

Ja klar war sie das, da würde ich doch nie dagegen wetten.

von Norbert (der_norbert)


Lesenswert?

Rahul D. schrieb:
> Warum nicht?
> Warum funktioniert das bei mir?

Wenn man es testet und es funktioniert, dann funktioniert es. Oh Wunder.
Es funktioniert DIESES Mal. Auf DIESER Architektur und mit DIESEM 
Compiler auf DIESEM Release-Stand.

Das mag für's Hobby oftmals genug sein.
Aber ernsthaft darauf verlassen solltest du dich besser nicht.

von Rahul D. (rahul)


Lesenswert?

Norbert schrieb:
> Es funktioniert DIESES Mal. Auf DIESER Architektur und mit DIESEM
> Compiler auf DIESEM Release-Stand.
Wir verwenden es auch in der Firma.
Liegt wohl daran, dass wir da nur Controller mit dem selben Endian 
verwenden (STM32 und AVR).
Der arm-Compiler ist inzwischen ein neues Release, und der "alte Kram" 
funktioniert trotzdem (wäre auch dämlich von Hitex, das einfach mal zu 
ändern)-

Norbert schrieb:
> Das mag für's Hobby oftmals genug sein.
> Aber ernsthaft darauf verlassen solltest du dich besser nicht.

Man sollte schon wissen was man tut...

von Bruno V. (bruno_v)


Lesenswert?

Rahul D. schrieb:
> Warum nicht?
> Warum funktioniert das bei mir?

In C sind unions nur Container für verschiedene Datentypen, aber nicht 
zur Wandlung.

Es kommt zudem mit so vielen Unbekannten (Alignment, Reihenfolge, 
interne Darstellung von z.B. Pointern oder Float), dass es keinen Sinn 
macht, dafür "allgemeingültige" Regeln aufzustellen.

die einzige "erlaubte" Umwandlung ist von einen Datentyp in Bytes und 
vice versa. Deshalb funktioniert z.B. memcpy.

Das es von den meisten trotzdem zuverlässig angewendet wird, geschenkt. 
Dass andere auf irgendwelche Serialisierungen bestehen, auch.

Für Beispiele des TOs nutze ich praktisch nur noch Funktionen/Makros, 
die z.B. den LED-Typ in BYTE konvertieren. Plus ein paar 
Compile-Time-Asserts, die zumindest Allignment und Size überwachen.
1
uint8_t Led2B(led1bits leds)
2
{
3
    return *((uint8_t *)&leds);
4
}
5
led1bits B2Led(uint8_t b)
6
{
7
    return *((led1bits *)&b);
8
}

oder
1
#define bacc(d) (*((uint8_t *) &d))
2
3
   uint8_t x = bacc(led1);
4
   ...
5
   bacc(led1) = 0x55;

von Joachim B. (jar)


Lesenswert?

Rahul D. schrieb:
> Man sollte schon wissen was man tut...

gilt aber nicht für die Systementscheider, die entscheiden nur und oft 
ohne Wissen, Wissen hindert zu oft an Entscheidungen.

von Johannes (zuberjo)


Lesenswert?

Norbert schrieb:
> Nemopuk schrieb:
>> Norbert schrieb:
>>> Nicht aber ...
>>
>> Wetten, genau das war aber die Intention dahinter?
>
> Ja klar war sie das, da würde ich doch nie dagegen wetten.

Viel Meinung, wenig Ahnung. Kein Plan was der Usecase wäre, wie es mit 
Evaluierung etc aussieht aber schon das Ergebnis kennen..

von Norbert (der_norbert)


Lesenswert?

Rahul D. schrieb:
> Man sollte schon wissen was man tut...

Da stimme ich dir zu, hatte ich allerdings als Voraussetzung angenommen.

Dann jedoch geht der Alte und es kommt der nächste Entwickler. Und 
verlässt sich auf saubere Programmierung in den zig-tausend Zeilen Code.
Nicht auf verborgene Tretminen.

von Norbert (der_norbert)


Lesenswert?

Johannes schrieb:
> Viel Meinung, wenig Ahnung. Kein Plan was der Usecase wäre, wie es mit
> Evaluierung etc aussieht aber schon das Ergebnis kennen..

Das ist nun hohles Geschwätz, wenn man dein ursprüngliches Statement 
auch nur halbwegs ernst nimmt.

von Rahul D. (rahul)


Lesenswert?

Joachim B. schrieb:
> gilt aber nicht für die Systementscheider, die entscheiden nur und oft
> ohne Wissen, Wissen hindert zu oft an Entscheidungen.

Politisches BlaBlaBla hat hier nichts zu suchen.
Selber machen! Besser machen!

von Rahul D. (rahul)


Lesenswert?

Norbert schrieb:
> Dann jedoch geht der Alte und es kommt der nächste Entwickler. Und
> verlässt sich auf saubere Programmierung in den zig-tausend Zeilen Code.
> Nicht auf verborgene Tretminen.

Gibt's bei uns nicht in der Form. Dann müssten gleich alle Softies 
hinschmeißen, und dafür ist unser Betriebsklima zu gut. (Und ich 
verlassen den Betrieb entweder als Rentner oder auf ner Bare).

Beitrag #7946733 wurde vom Autor gelöscht.
von Johannes (zuberjo)


Lesenswert?

Norbert schrieb:
> Das ist nun hohles Geschwätz, wenn man dein ursprüngliches Statement
> auch nur halbwegs ernst nimmt.

Nein, nicht unbedingt. Zb eine MCU als Schnittstelle zwischen Elektronik 
und SPS. In einer Statusvariablen werden per Interrupt Bits gesetzt oder 
gelöscht. Der MCU ist hier der Datentyp egal. Die Statusvariable kann zb 
ein 16 Bit Short sein oder ein Struct. Wenn der Struct im Speicher die 
Größe einer Short hat, dann kann er auch als solcher gecastet und an die 
SPS weitergeleitet werden. Mir geht es primär um die Lesbarkeit von 
Code. Dies wäre bei einem Struct besser als mit Bitoperatoren

von Joachim B. (jar)


Lesenswert?

Rahul D. schrieb:
> Politisches BlaBlaBla

nix Politik, Erfahrung aus 12 Jahren Industriezeit, wenn du da an 
Politik denkst kann ich dir nicht übelnehmen.

von Norbert (der_norbert)


Lesenswert?

Johannes schrieb:
> Mir geht es primär um die Lesbarkeit von
> Code. Dies wäre bei einem Struct besser als mit Bitoperatoren

Eigentlich ist schon alles gesagt, daher vielleicht nur noch folgender 
(ganz allgemein geltender) Gedanke:
Wer mit Bitoperationen und einfacher boolescher Algebra in ›C‹ nicht 
klarkommt, der sollte besser erneut lesen und lernen. Oder eine 
einfachere Programmiersprache (vielleicht mit BA beginnend…) benutzen.

Die üblichen AND, OR, XOR und NOT Operationen lesen sich jedenfalls 
praktisch von allein und brauchen keinen syntaktischen Gehgips.

von Harald K. (kirnbichler)


Lesenswert?

Johannes schrieb:
> uint8_t var
> enum{
>   Bit0 = 1,
>   Bit1 = 2
> }
> Bit setzen: var |= (1<<Bit0)
> Bit löschen dann var &= ~(1<<Bit0)

Hmm. Interessante Defintion für "Bit0".

Welchen Wert hätte in Deinem enum der Wert "Bit7"?

von Johannes (zuberjo)


Lesenswert?

Harald K. schrieb:
> Welchen Wert hätte in Deinem enum der Wert "Bit7"?

War ein Beispiel und keine Stackoverflow Lösungsfunktion. Kanns du aber 
dennoch gerne per copy paste verwenden und dich danach wundern warum es 
nicht geht.

von Μαtthias W. (matthias) Benutzerseite


Lesenswert?

Johannes schrieb:
> Basic spielt heute im E-Technik Studium keine Rolle mehr. C, C++, Java,
> C# und geringfügig Assembler. Zusätzlich noch ein wenig VHDL und mehr
> brauchts auch nicht im Berufsleben als E-Techniker.

Stand heute würde ich da mindestens eine Scriptsprache (aktuell wohl 
Python) und evtl. noch Rust ergänzen. Bin jetzt Mitte 40, mit ASM und C 
"groß" geworden und würde mir nicht zutrauen zu sagen das das in der 
Zeit gelernte C++, Perl und Python für das verbleibende Berufsleben 
reicht. Programmiersprachen kommen und gehen. Für die reine 
Anwendungsentwicklung übernimmt die KI gerade jede Menge 
Programmiersprachengefummel. Und auch im maschinennahen Bereich wird das 
erschreckenderweise immer besser.

Matthias

von Harald K. (kirnbichler)


Lesenswert?

Johannes schrieb:
> War ein Beispiel und keine Stackoverflow Lösungsfunktion.

War ein fehlerhaftes Beispiel.

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

Norbert schrieb:
> Wenn man sich jetzt noch daran erinnert, dass man aus einer Union immer
> nur das ausliest, was man zuvor hinein geschrieben hat, dann ist alles
> prima.
> * uint8_t → uint8_t
> * bits → bits
>
> Nicht aber:
> * uint8_t → bits
> * bits → uint8_t

Doch, das ist kein Problem da es um GCC geht.

https://gcc.gnu.org/bugs/#nonbugs_c
1
> To fix the code above, you can use a union instead of a cast
2
> (note that this is a GCC extension which might not work with
3
> other compilers)

Soweit ich weiß ist es auch in neueren C/C++ Standards erlaubt; bin 
jetzt aber zu faul zum suchen.

von Alexander (alecxs)


Lesenswert?

Rahul D. schrieb:
> Da das Ursprungsthema abgehandelt ist, kann man auch wieder etwas
> offtopic werden...

Ist denn das Problem der Endianess mit union umschifft?

von Harald K. (kirnbichler)


Lesenswert?

Alexander schrieb:
> Ist denn das Problem der Endianess mit union umschifft?

Bei einem 8-Bit-Datentyp?

Es gibt keine unterschiedliche Bitreihenfolge, nur eine unterschiedliche 
Bytereihenfolge.

0x1234 liegt im Big-Endian-Fall als 0x12 0x34 im Speicher
und im Little-Endian-Fall als 0x34 0x12.

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

Harald K. schrieb:
> Es gibt keine unterschiedliche Bitreihenfolge, nur eine unterschiedliche
> Bytereihenfolge.
1
// gcc bit.c -o bit.x && ./bit.x
2
3
#include <stdio.h>
4
#include <stdint.h>
5
6
typedef union
7
{
8
    struct
9
    {
10
        uint8_t b0:1, b1:1, b2:1, b3:1, b4:1, b5:1, b6:1, b7:1;
11
    };
12
    uint8_t byte;
13
} data_t;
14
15
data_t data;
16
17
int main (void)
18
{
19
    data.b0 = 1;
20
    printf ("data.byte = 0x%x\n", data.byte);
21
    return 0;
22
}

Auf IBM POWER7 8231-E2B (big-endian):
1
$ gcc bit.c -o bit.x && ./bit.x
2
data.byte = 0x80

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

...dito auf Sun LDOM (big-endian) UltraSparc T5 (sparc64):
1
$ gcc bit.c -o bit.x && ./bit.x
2
data.byte = 0x80

von Harald K. (kirnbichler)


Lesenswert?

Na gut. Dann sind Bitfelder für so eine Anwendung komplett sinnlos.

Danke für die Demonstration.

von Alexander (alecxs)


Lesenswert?

Auf dem ESP32 habe ich die Structs in der richtigen Bytefolge aber mit 
absteigender Bitfolge anlegen müssen.
1
struct {
2
       uint8_t bit7  :1;
3
       uint8_t bit6  :1;
4
       uint8_t bit5  :1;
5
       uint8_t bit4  :1;
6
       uint8_t bit3  :1;
7
       uint8_t bit2  :1;
8
       uint8_t bit1  :1;
9
       uint8_t bit0  :1;
10
11
       uint8_t bit15 :1;
12
       uint8_t bit14 :1;
13
       uint8_t bit13 :1;
14
       uint8_t bit12 :1;
15
       uint8_t bit11 :1;
16
       uint8_t bit10 :1;
17
       uint8_t bit9  :1;
18
       uint8_t bit8  :1;
19
    } byte;

von Harald K. (kirnbichler)


Lesenswert?

Dann kann ich das eben von mir gesagte nur nochmal wiederholen:

Bitfelder sind nutzlos.

von Nemopuk (nemopuk)


Lesenswert?

Das wäre mir zu fehlerträchtig. Es gibt genug etablierte Alternativen, 
die sicher und verständlich sind.

von Norbert (der_norbert)


Lesenswert?

Harald K. schrieb:
> Dann kann ich das eben von mir gesagte nur nochmal wiederholen:
>
> Bitfelder sind nutzlos.

Ich würde sie jetzt nicht als nutzlos ansehen, nur sollte man sie eben 
nicht als allgemein gültiges Konvertierungswerkzeug misshandeln.

Zumindest früher™ konnte man damit wertvollen** Platz sparen, wenn man 
nur eine größere Menge einzelner Bits speichern wollte.

**Im wahrsten Sinne des Wortes

von Arduino F. (Firma: Gast) (arduinof)


Lesenswert?

Rahul D. schrieb:
>>        bool bit7 :1;
>>     };
>
> Bool ist doch ein int und das ist 16Bit breit.

Bool ist an der Stelle nur 1 Bit breit, dank des :1

von Alexander (alecxs)


Lesenswert?

Für dreckige Hobbybasteleien reichts, es muss ja nicht MISRA konform 
sein.

von Bruno V. (bruno_v)


Lesenswert?

Alexander schrieb:
> Auf dem ESP32 habe ich die Structs in der richtigen Bytefolge aber mit
> absteigender Bitfolge anlegen müssen.

i.d.R. kann man die Bit-Reihenfolge mit einem Compilerschalter ändern.

Bei einer Big-Endian-Maschine, gibt es das Problem, dass man 
unterschiedliche Anordnungen braucht, je nachdem ob man Byteweise darauf 
zugreifen möchte oder mit breiteren Werten (unsigned short, int oder 
long).

von Rahul D. (rahul)


Lesenswert?

Μαtthias W. schrieb:
> Programmiersprachen kommen und gehen.

Außer welche mit C im Namen.

Alexander schrieb:
> Ist denn das Problem der Endianess mit union umschifft?

Das war nicht die Ursprungsfrage.

Arduino F. schrieb:
> Bool ist an der Stelle nur 1 Bit breit, dank des :1

Nach meinem Verständnis beschreibt Bool den Typ, von dem die struct 
abgeleitet ist. Bool ist eh meist nur eine Makroname, der durch einen 
anderen ersetzt wird (z.B. int).
Solange der Prozessor keine Möglichkeit der 1-Bit-Adressierung (wie 
8051) hat, wird der Compiler daraus immer Bitschubscherei machen.

von Alexander (alecxs)


Lesenswert?

Rahul D. schrieb:
> Das war nicht die Ursprungsfrage.

Martin S. schrieb:
> Byte bitweise und als ganzes zugreifen als Datentyp in c

Die Frage sehe ich noch nicht gelöst, das geht wohl nur sicher mit 
Bitmasken.

Oder man nutzt predefined Macros (Gnu oder Posix?) sofern für Bitfolge 
etwas  derartiges vorhanden. Aus der Byte Endianess ableiten reicht in 
der Praxis vermutlich.
1
typedef union {
2
    struct bits_t {
3
#if __BYTE_ORDER == __LITTLE_ENDIAN
4
        bool bit0 : 1;
5
        bool bit1 : 1;
6
        bool bit2 : 1;
7
        bool bit3 : 1;
8
        bool bit4 : 1;
9
        bool bit5 : 1;
10
        bool bit6 : 1;
11
        bool bit7 : 1;
12
#elif __BYTE_ORDER == __BIG_ENDIAN
13
        bool bit7 : 1;
14
        bool bit6 : 1;
15
        bool bit5 : 1;
16
        bool bit4 : 1;
17
        bool bit3 : 1;
18
        bool bit2 : 1;
19
        bool bit1 : 1;
20
        bool bit0 : 1;
21
#endif
22
    } __attribute__((__packed__)) bits;
23
    uint8_t byte;
24
} bitfield_t;

: Bearbeitet durch User
von Rahul D. (rahul)


Lesenswert?

Alexander schrieb:
> Aus der Byteendianess ableiten reicht in
> der Praxis vermutlich.

Wenn man unbedingt Endians durcheinanderschmeissen will...
Der Wunsch nach "Portabilität" findet irgendwo sein Ende.

von Joachim B. (jar)


Lesenswert?

Rahul D. schrieb:
> Der Wunsch nach "Portabilität" findet irgendwo sein Ende.

Alles findet irgenwo ein Ende, selbst unser Leben, selbst die Sonne, 
also ist dieser Satz eine Nullinformation und überflüssig.

Bis dahin kann man (oder ich) auf zu kleine Speicher eben diesen 
sparsamer nutzen wenn es benötigt wird.

von Cyblord -. (cyblord)


Lesenswert?

Joachim B. schrieb:
> Rahul D. schrieb:
>> Der Wunsch nach "Portabilität" findet irgendwo sein Ende.
>
> Alles findet irgenwo ein Ende, selbst unser Leben, selbst die Sonne,
> also ist dieser Satz eine Nullinformation und überflüssig.

Nein er hat recht. Sie findet ihr Ende in einer gut gemachten HAL oder 
in HW-unabhängigen Modulen.
Hat man sowas, macht es also richtig, kann man über die Methode WIE man 
letztlich einen Pin setzt nur lächeln. Es hat keine Bedeutung mehr und 
es lohnt nicht sich damit zu verkünsteln. Weil es dann nur noch an ganz 
wenigen Stellen im Programm vorkommt. Und das ist mal nicht die 
Applikationslogik.

> Bis dahin kann man (oder ich) auf zu kleine Speicher eben diesen
> sparsamer nutzen wenn es benötigt wird.

Weil man oder du einfach keine Ahnung von guter SW-Entwicklung haben und 
gute und sinnvolle Abstraktion nicht verstehen geschweige denn 
implementieren können.
Speicher ist heute sicher nicht dein Problem. Es ist wenn dann eine 
Ausrede für fehlende Skills.

: Bearbeitet durch User
von Thilo R. (harfner)


Lesenswert?

Ich mache jetzt mal den Erbsenzähler: der C Standard legt die 
Reihenfolge der Bitfields innerhalb eines Bytes nicht fest. Theoretisch 
könnten verschiedene Compiler für die gleiche Plattform das 
unterschiedlich handhaben. Und das ist streng genommen unabhängig von 
Endianess.
In der Praxis fällt beides zusammen, man hat also nur die beiden Fälle.

Das führt dazu, dass der wichtigere der beiden Anwendungsfälle von 
Bitfields nicht sicher funktioniert.  Es bleibt nur der Aspekt "Platz 
sparen".

von M.A. S. (mse2)


Lesenswert?

Joachim B. schrieb:
> komisch in meinem E-Technik Studium zum Diplomingenieur war Basic am
> Terminal vom Großrechner Standard.
Basic als Standard auf einem Großrechner und das an einer Uni?
Mich würde ernsthaft interessieren, wann und wo das gewesen sein soll.

1985 an der TU Berlin hat man E-Technikstudenten im ersten Semester 
Programmieren mit Pascal näherzubringen versucht. Das lief auch auf den 
Terminals eines Großrechners.

von Martin S. (mmaddin)


Lesenswert?

Hallo,

ich nutze das in dieser Form:

typedef union
{
  struct
  {
   uint32_t btn1  :1,
            btn2  :1,
            btn3  :1,
            btn4  :1,
            btn5  :1,
            btn6  :1,
            btn7  :1,
            btn8  :1,
            btn9  :1,
            btn10 :1,
            btn11 :1,
            btn12 :1,
            btn13 :1,
            btn14 :1,
            btn15 :1,
            btn16 :1,
            btn17 :1,
            btn18 :1,
            btn19 :1,
            btn20 :1,
            btn21 :1,
            btn22 :1,
            btn23 :1,
            btn24 :1,
            btn25 :1,
            btn26 :1,
            btn27 :1,
            btn28 :1,
            btn29 :1,
            btn30 :1,
            btn31 :1,
            btn32 :1;
  };
  struct
  {
     uint32_t byte1 :8,
              byte2 :8,
              byte3 :8,
              byte4 :8;
  };
  uint8_t byte[4];
  uint32_t all;
}buttons_t;

Die Struktur benötigt wie erwartet in Summe 4 Bytes. "all" nutze ich um 
alles auf null zu setzen, die bytes meistens in den 
Verarbeitungsroutinen und die Bitzugriffe dann in den Menüs oder im 
höheren code. Passt ganz gut für meine Zwecke. Klar gibt es viele Wege 
nach Rom in C, aber das hier gefällt mir momentan ganz gut, habe eine 
Zeit lang auch vieles mit Makros gemacht...

Danke nochmals.

von Alexander (alecxs)


Lesenswert?

Wie gesagt das ist Glück wenn es bei Dir so funktionieren sollte 
(Bitfolge getestet?) Ebenso Deine byte Zugriffe sind von Endianness 
abhängig und nicht portabel. Hinzu kommt Padding compilerabhängig fürs 
Alignment.

von Martin S. (mmaddin)


Lesenswert?

Alexander schrieb:
> Bitfolge getestet?

Ja, da ich sie alle nutze, außer bei "all" damit setze ich ja nur auf 
null.

Alexander schrieb:
> sind von Endianness
> abhängig und nicht portabel

Ist mir bekannt das Thema.

Alexander schrieb:
> Padding

Sagt mir nichts....aber hier sind die Anteile alle doch immer 32 Bit 
groß...

von Bruno V. (bruno_v)


Lesenswert?

Alexander schrieb:
> Wie gesagt das ist Glück wenn es bei Dir so funktionieren sollte

Manchmal muss man auch mal einen Nagel in die Wand schlagen. Sprich: 
Ausprobieren ob es klappt. Oder die Implementierungsspezifischen 
Eigenschaften des Compilers studieren und es für das eigene System zum 
Laufen bringen ohne den Anspruch, dass alles so wunderbar kompatibel 
ist.

Eine Mathe-Lib oder ein Protokoll-Konverter sollte sich nicht auf ein 
Padding verlassen, geschenkt.

Aber die Vorstellung, dass jeder HW-Zugriff auch für 9Bit-Chars, beide 
Endians und Einer-Komplement funktionieren muss, ist weltfremd.

Die meisten Entwickler haben schon Probleme mit Format-Specifiern in 
einem konkreten System. Der "richtige" Weg für alle Int-Größen macht das 
nicht zuverlässiger sondern fragiler.

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.