Forum: Mikrocontroller und Digitale Elektronik Einzelne Bit in Bitfeld in for Schleife ansprechen


von Rick M. (rick00)


Lesenswert?

Hallo!

Ich habe in C/C++ (ATmega328) zum Speichern der Ausgangszustände ein 
Bitfeld definiert:
1
struct Ausgaenge        // jeweils 1 Bit fuer Speicherung der Zustaende der Ausgänge
2
{
3
        uint16_t A1:1;
4
        uint16_t A2:1;
5
        uint16_t A3:1;
6
        uint16_t A4:1;
7
        uint16_t A5:1;
8
        uint16_t A6:1;
9
        uint16_t A7:1;
10
        uint16_t A8:1;
11
        uint16_t A9:1;
12
        uint16_t A10:1;
13
        uint16_t A11:1;
14
        uint16_t A12:1;
15
        uint16_t A13:1;
16
}
17
Ausgang;

Nun wollte ich folgendes machen:
1
for (uint8_t i=1; i<=13; i++)
2
    {
3
        Serial.print("A");
4
        Serial.print(i);
5
        Serial.print(": ");
6
        Serial.println(Ausgang.A(i));

Funktioniert aber leider so nicht.
Was mache ich falsch?
Können einzelne Bits in Bitfelder überhaupt über Variablen so 
angesprochen werden?
Ich hab mir jetzt so einige Diskussionen über Bitfelder durchgelesen und 
das Gefühl bekommen lieber die Finger davon zu lassen und stattdessen 
ganz klassich einfach ein ganzes Byte pro Merker zu verwenden.
C hat anscheinend keine vernünftigen "Werkzeuge" um einzelne Bit zu 
adressieren. Zumindest habe ich den Eindruck bekommen.
Ist dem so?

Danke!

Gruß
Rick

von Walter T. (nicolas)


Lesenswert?

A13 ist ein Variablenname und damit kein Index A[13]. Selbst wenn es ein 
Index wäre, würde er nicht mit runden Klammern angesprochen.

(Es gibt Sprachen, in denen sich Feldnamen als Variable ansprechen 
lassen, aber C++ gehört nicht dazu. In Matlab wäre Ausgang.("A13") ein 
valider Ausdruck.)

(Für die Variablennamen in struct/Bitfields gilt das Gleiche wie für 
Variablennamen in anderen Speicherbereichen.)

Der sinnvolle Anwendungsbereich von Bitfeldern ist sehr begrenzt.
Wahrscheinlich lässt sich Dein Problem auf irgendeine andere Weise 
besser lösen.

: Bearbeitet durch User
von Oliver S. (oliverso)


Lesenswert?

Zwar könnte man sich eine halblegale Lösung mit einer Union basteln, nur 
erfordert die dann die passende Bitmaske, und damit ist der ganze Sinn 
des Bitfields dahin. Dann kannst du auch gleich auf dem uint arbeiten.

Da die Zustände der Ausgänge aber doch eh in den PORTn-Registern stehen, 
ist der Sinn der ganzen Aktion sowieso fraglich.

Oliver

: Bearbeitet durch User
von Rick M. (rick00)


Lesenswert?

Oliver S. schrieb:
> Da die Zustände der Ausgänge aber doch eh in den PORTn-Registern stehen,
> ist der Sinn der ganzen Aktion sowieso fraglich.

Es handelt sich hierbei nicht um die Ausgänge des uC, sondern um 
Ausgänge einer Regelung deren Status über den DL-Bus eingelesen wurden.

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


Lesenswert?

Rick M. schrieb:
> C hat anscheinend keine vernünftigen "Werkzeuge" um einzelne Bit zu
> adressieren.
Natürlich nicht!

Aber dein C++ kann das!
z.B. durch überladen des [] Operators.
Die Arduino EEPROM Lib tut ähnliches. Da kannste dir evtl. was 
abschauen.

: Bearbeitet durch User
von (prx) A. K. (prx)


Lesenswert?

Rick M. schrieb:
> Ich hab mir jetzt so einige Diskussionen über Bitfelder durchgelesen und
> das Gefühl bekommen lieber die Finger davon zu lassen

👍

von Daniel A. (daniel-a)


Lesenswert?

Rick M. schrieb:
> Ich habe in C/C++ (ATmega328) zum Speichern der Ausgangszustände ein

C und C++ ist nicht das selbe! Das Serial.print sieht mir nach Arduino 
aus, also C++.

Wenn du mit ganzen Bytes arbeiten würdest "unsigned char 
A[(13+CHAR_BIT-1)/CHAR_BIT];" könntest du z.B. mit "A[i/CHAR_BIT] & 
(1<<(i%CHAR_BIT))" ein bestimmtes Bit abfragen. (hier ist i 0 relativ!).

Von Bitfeldern kann man keine Arrays haben, daher kann man da nicht 
einfach so eins per index abfragen. Man könnte dafür aber eine Funktion 
mit switch case anlegen:
1
bool get_bit(Ausgang a, int i){
2
  switch(i){
3
    case 0: return a.A0;
4
    case 1: return a.A1;
5
    case 2: return a.A2;
6
    ...
7
  }
8
}

Da wir hier C++ haben, könntest du auch den [] und = Operator überladen. 
Ich hab schon lange kein C++ mehr gemacht, irgend was in die richtung:
1
class BitRef {
2
private:
3
  const int bit;
4
  unsigned char*const byte;
5
public:
6
  BitRef(unsigned char* b, int i) : byte(b), bit(i) {
7
  }
8
  operator bool() const {
9
    return *this->byte & (1<<this->bit);
10
  }
11
  bool operator=(bool b){
12
    if(b) *this->byte |= (1<<this->bit);
13
    else *this->byte &= ~(1<<this->bit);
14
  }
15
};
16
struct Ausgaenge {
17
  BitRef operator[](int i){
18
    return BitRef(this.A[i/CHAR_BIT], i);
19
  }
20
  ...
21
};

von Georg M. (g_m)


Lesenswert?

Rick M. schrieb:
> ganz klassich einfach ein ganzes Byte pro Merker zu verwenden.

Ja, das ist einfach und schnell.


Rick M. schrieb:
> C hat anscheinend keine vernünftigen "Werkzeuge" um einzelne Bit zu
> adressieren.

Überhaupt kein Problem.
1
 (a >> i) & 1

von Torsten B. (butterbrotstern)


Lesenswert?

> (a >> i) & 1
Oft ist es günstiger, a & i zu verwenden und dann i zu schieben, vor 
allem, wenn man mehrere Bits hintereinander abfragen will. i erfüllt 
zwei Aufgaben:
Bitmaske und Schleifenvariable (die nicht gezählt, sondern geschoben 
wird).
Wichtig ist ja nur, ob es gleich oder ungleich 0 ist.

  for(uint16_t i=1<<13; i; i>>=1){Serial.println(a&i?"1":"0");}

von Cyblord -. (cyblord)


Lesenswert?

Immer diese blöden Bitfelder und dann immer von Anfängern. Leute, lasst 
das einfach. Oder macht es wenigstens wenn ihr euch besser auskennt.
Bitfelder bringen so wenig. Arbeitet mit Bytes. Macht es euch leichter. 
Kapselt Funktionalität gut und sauber in Funktionen. Nicht in 
Bitfeldern.

: Bearbeitet durch User
von Obelix X. (obelix)


Lesenswert?

1
#include <stdlib.h>
2
#include <stdio.h>
3
#include <stdint.h>
4
#include <stdbool.h>
5
#include <string.h>
6
#include <ctype.h>
7
8
union {
9
  uint16_t allbits;
10
  struct {
11
    uint16_t bit0:1;
12
    uint16_t bit1:1;
13
    uint16_t bit2:1;
14
    uint16_t bit3:1;
15
    uint16_t bit4:1;
16
    uint16_t bit5:1;
17
    uint16_t bit6:1;
18
    uint16_t bit7:1;
19
    uint16_t bit8:1;
20
    uint16_t bit9:1;
21
    uint16_t bit10:1;
22
    uint16_t bit11:1;
23
    uint16_t bit12:1;
24
    uint16_t bit13:1;
25
    uint16_t bit14:1;
26
    uint16_t bit15:1;
27
  } bit;
28
} mybitfield;
29
30
int main() {
31
  mybitfield.allbits = 0x0102;
32
33
  printf("Bit 0 = %d\n", mybitfield.bit.bit0);
34
  printf("Bit 1 = %d\n", mybitfield.bit.bit1);
35
36
  printf("\n");
37
38
  for (uint16_t i=0; i<16; i++)
39
  {
40
    printf("Bit %d = %d\n", i , (mybitfield.allbits >> i) & 1 );    
41
  }
42
43
  printf("\n");
44
45
  return 0;
46
}

von Niklas G. (erlkoenig) Benutzerseite


Lesenswert?

Torsten B. schrieb:
> Oft ist es günstiger, a & i zu verwenden und dann i zu schieben, vor
> allem, wenn man mehrere Bits hintereinander abfragen will. i erfüllt
> zwei Aufgaben:

Genau richtig, insbesondere auch weil die AVR keinen Barrelshifter haben 
und (1 << i) langsam ist (O(i) Takte). Okay, bei der Ausgabe via 
Serialport spielt das keine Rolle, aber an anderer Stelle vielleicht 
schon.

In C++ gibt es auch noch std::bitset was ziemlich genau das macht:

Daniel A. schrieb:
> Da wir hier C++ haben, könntest du auch den [] und = Operator überladen.

Nur leider liefert der AVR-GCC ja die C++ stdlib nicht mit.

: Bearbeitet durch User
von Obelix X. (obelix)


Lesenswert?

Mal ne doofe frage zu meinem eigenen Code oben ...

Wie müsste ich meine Anfrage für eine KI formulieren, damit ich einen 
Code wie den von mir oben geschrieben bekomme?

Gestern gab es einen Thread über KI-Code generieren...


Man kann den Bits dann natürlich auch gleich einen Namen verpassen
1
union {
2
  uint16_t allbits;
3
  struct {
4
    uint16_t drucker:1;
5
    uint16_t endschalter1:1;
6
    uint16_t overtemp:1;
7
    uint16_t foobar:1;
8
.
9
.
10
.
11
  } status;
12
} mybitfield;

: Bearbeitet durch User
von Georg M. (g_m)


Lesenswert?

Torsten B. schrieb:
> a & i

Sorry, das verstehe ich nicht.

von Georg M. (g_m)


Angehängte Dateien:

Lesenswert?

Cyblord -. schrieb:
> Immer diese blöden Bitfelder und dann immer von Anfängern.

Bitfelder stehen am Anfang des Programmierens. Ohne Bitfelder kann man 
den Mikrocontroller nicht programmieren.

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


Lesenswert?

Niklas G. schrieb:
> Daniel A. schrieb:
>> Da wir hier C++ haben, könntest du auch den [] und = Operator überladen.
>
> Nur leider liefert der AVR-GCC ja die C++ stdlib nicht mit.
Das ist dabei kein Hinderungsgund!

Niklas G. schrieb:
> In C++ gibt es auch noch std::bitset
Hier allerdings schon.


Wobei es auch für AVR eine  Libstdc++ Implementierung gibt.
Nicht vollständig, aber immerhin.

: Bearbeitet durch User
von Arduino F. (Firma: Gast) (arduinof)


Lesenswert?

Georg M. schrieb:
> Bitfelder stehen am Anfang des Programmierens. Ohne Bitfelder kann man
> den Mikrocontroller nicht programmieren.

Ihm möchte Leute für blöd erklären, da ist ihm jedes Mittel recht.

: Bearbeitet durch User
von Frank M. (ukw) (Moderator) Benutzerseite


Lesenswert?

Georg M. schrieb:
> Ohne Bitfelder kann man den Mikrocontroller nicht programmieren.

Falsch.

Siehe Artikel Bitmanipulation

von Bruno V. (bruno_v)


Lesenswert?

Man kann das auch stur runterhacken. Nicht schön, keine statische oder 
dynamische Erkennung von Fehlern, die Typen sind unzweckmäßig und der 
Aufwand (bei mehr Pins) groß.

Aber es läuft erstmal und man kann weitermachen. Und sich später um 
Alternativen bemühen. Und wenn man mehrere Ports braucht, wird man 
Muster erkennen, die man vereinheitlichen kann.
1
uint16_t GetAusgang(int i)
2
{
3
    switch(i)
4
    {
5
    case 1: return Ausgang.A1;
6
    case 2: return Ausgang.A2;
7
    case 3: return Ausgang.A3;
8
    ...
9
    case 13: return Ausgang.A13;
10
    }
11
    return 0; /* wasimmer der Default sein soll im Fehlerfall */
12
}
13
14
void SetAusgang(uint16_t s)
15
{
16
    switch(i)
17
    {
18
    case 1: Ausgang.A1 = s; break;
19
    case 2: Ausgang.A2 = s; break;
20
    case 3: Ausgang.A3 = s; break;
21
    ...
22
    case 13: Ausgang.A13 = s; break;
23
    }
24
}

von Frank M. (ukw) (Moderator) Benutzerseite


Lesenswert?

Georg M. schrieb:
> Torsten B. schrieb:
>> a & i
>
> Sorry, das verstehe ich nicht.

Ja, ist ein wenig ungünstig ausgedrückt. Mit i ist hier eine Maske 
gemeint.

Beispiel:
1
  uint16_t mask = 1;
2
  for (uint16_t i=0; i<16; i++)
3
  {
4
    printf("Bit %d = %d\n", i , (mybitfield.allbits & mask) ? 1 : 0);
5
    mask <<= 1;
6
  }

Hier wird der Verschiebeoperator mit der Konstante 1 verwendet. Das ist 
auf einem AVR wesentlich effizienter als eine Verschiebung mit einer 
variablen Anzahl von Bits.

: Bearbeitet durch Moderator
von Georg M. (g_m)


Lesenswert?

Frank M. schrieb:
> Falsch.

Was falsch?


Frank M. schrieb:
> Siehe Artikel Bitmanipulation

Ja, darum geht es eben. Bitmanipulationen.

von Mikro 7. (mikro77)


Lesenswert?

Rick M. schrieb:
> Ich habe in C/C++ (ATmega328) zum Speichern der Ausgangszustände ein
> Bitfeld definiert:

Spricht etwas gegen std::bitset? (C++)
https://en.cppreference.com/w/cpp/utility/bitset

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


Lesenswert?

Mikro 7. schrieb:
> Spricht etwas gegen std::bitset? (C++)

Ja, es liegt nicht der der Toolchain bei.

von (prx) A. K. (prx)


Lesenswert?

Georg M. schrieb:
> Bitfelder stehen am Anfang des Programmierens.

Mitnichten.

> Ohne Bitfelder kann man den Mikrocontroller nicht programmieren.

Man hat in C schon Hardware-nahe programmiert, als es Bitfelder 
überhaupt noch nicht gab. Für solche Programmierung wurde C ursprünglich 
entwickelt.

Bitfelder wurden nicht für die Abbildung von Hardware in die Sprache 
eingebaut, sondern um Daten platzsparend unterzubringen. RAM war teuer, 
Disks waren es auch.

: Bearbeitet durch User
von Frank M. (ukw) (Moderator) Benutzerseite


Lesenswert?

Georg M. schrieb:
> Was falsch?

Man braucht keine Bitfelder, um Bits zu manipulieren, siehe 
Bitmanipulation <-- draufklicken!

Von daher ist Deine Aussage:

> Ohne Bitfelder kann man den Mikrocontroller nicht programmieren.

komplett falsch.

q.e.d.

Ich würde sie auch niemals einem Anfänger empfehlen. Bitfelder sind 
höchst inkompatibler Blödsinn.

: Bearbeitet durch Moderator
von Georg M. (g_m)


Lesenswert?

(prx) A. K. schrieb:
> Man hat in C schon Hardware-nahe programmiert, als es Bitfelder
> überhaupt noch nicht gab.

Also standen Bits irgendwie ganz chaotisch, ungeordnet im Speicher?

von Rahul D. (rahul)


Lesenswert?

Georg M. schrieb:
> Also standen Bits irgendwie ganz chaotisch, ungeordnet im Speicher?

Bitfelder sind eine Compiler-Erweiterung.
Speicher sind i.d.R. byteweise (oder in Vielfachen davon) organisiert.

Die kann auch sehr einfach als Bitmaske ansprechen.

Ansonsten: Troll woanders!

von Niklas G. (erlkoenig) Benutzerseite


Lesenswert?

Rahul D. schrieb:
> Bitfelder sind eine Compiler-Erweiterung.

Nein, die sind im C bzw. C++ Standard spezifiziert.

von Frank M. (ukw) (Moderator) Benutzerseite


Lesenswert?

Georg M. schrieb:
> (prx) A. K. schrieb:
>> Man hat in C schon Hardware-nahe programmiert, als es Bitfelder
>> überhaupt noch nicht gab.
>
> Also standen Bits irgendwie ganz chaotisch, ungeordnet im Speicher?

Man kann mit den Operatoren ~, <<, >>, & und | sämtliche Bitoperationen 
machen, die man braucht. Bitfelder, so wie sie in C definiert sind, sind 
überhaupt kein Muss, um Bitmanipulationen vorzunehmen.

Bitfelder in C sind - wie es A.K. schon sagte - dazu gedacht, 
Informationen kompakt zu speichern. Mit Bitmanipulationen hat das 
überhaupt nichts zu tun. Die Brücke zu Bitmanipulationen kann man nur 
bauen, indem man (höchst inkompatbile) Annahmen über die verwendete 
Hardware (Stichwort: Endianess) macht. Das ist aber niemals im Sinne der 
Erfinder der C-Bitfelder gewesen.

: Bearbeitet durch Moderator
von Georg M. (g_m)


Lesenswert?

Frank M. schrieb:
>> Ohne Bitfelder kann man den Mikrocontroller nicht programmieren.
>
> komplett falsch.
>
> q.e.d.

Wie programmiert man die Register? Betrachtet man sie als 
Zahlen/Variablen, oder als Bitfelder?


"...einzelne Bits oder Gruppen von Bits aneinandergereiht werden"
https://de.wikipedia.org/wiki/Bitfeld

von Bruno V. (bruno_v)


Lesenswert?

Georg M. schrieb:
> Also standen Bits irgendwie ganz chaotisch, ungeordnet im Speicher?

nicht chaotisch. Sondern auf eine von mehreren  möglichen 
spezifizierten Weisen.

"Mehrere mögliche" bedeutet nicht portabel, jederzeit änderbar, nicht 
unbedingt so, wie man es braucht, per Compiler-Option auf einmal ganz 
anders.

Beispielsweise ist nicht klar, ob A1 im OP das höchst- oder 
niederwertigste Bit ist (also Daten-Bit "D0" oder "D15" repräsentiert).

: Bearbeitet durch User
von (prx) A. K. (prx)


Lesenswert?

Niklas G. schrieb:
> Nein, die sind im C bzw. C++ Standard spezifiziert.

Es gab C in früher Version bereits, als es einen Standard dafür noch 
nicht gab, nicht einmal die K&R Erstausgabe.

von Frank M. (ukw) (Moderator) Benutzerseite


Lesenswert?

Georg M. schrieb:
> Wie programmiert man die Register?

Zum Beispiel für eine Initialisierung eines UARTs auf eienm AVR so:
1
#if USE_2X
2
    UART0_UCSRA |= (1<<UART0_U2X);
3
#else
4
    UART0_UCSRA &= ~(1<<UART0_U2X);
5
#endif
6
    UART0_UCSRC = UART0_UCSZ1_BIT_VALUE | UART0_UCSZ0_BIT_VALUE | UART0_URSEL_BIT_VALUE;
7
    UART0_UCSRB |= UART0_TXEN_BIT_VALUE;                                                            // enable UART TX

Siehst Du da Code, wo C-Bitfelder genutzt werden?

> Betrachtet man sie als Zahlen/Variablen, oder als Bitfelder?

Man kann sie als Bitfelder betrachten, ohne C-Bitfelder zu benutzen. 
Auch Dein zitierter Wikipedia-Artikel modifiziert mit den C-Bitfeldern 
keine Hardware-Register!

Falls Du es immer noch nicht gemerkt hast: Es geht um die Verwendung von 
C-Bitfeldern und nicht allgemein um Bitfelder, an denen Du Dich 
aufhängst.

: Bearbeitet durch Moderator
von Daniel A. (daniel-a)


Lesenswert?

Ich hatte mal einen echt doofen Bug mit anonymen Bitfeldern. Bei "struct 
{ int : 8; int y : sizeof(int)*CHAR_BIT-8; } x = {0}; ...", könnte man 
ja meinen, das wird alles genullt. Das anonyme Bitfeld aber nicht 
unbedingt...

von (prx) A. K. (prx)


Lesenswert?

Das wäre nur bei statischen Daten ein Bug der Entwicklungsumgebung, weil 
nur die komplett genullt werden, Füllbits engeschlossen.

Bitfelder sind eher schwach definiert, was die Sprache angeht. Wer 
solche Konstrukte für zuverlässige Abbildung von Hardware nutzen will, 
sollte auf Ada umsteigen. Da wurde das von vorneherein genau definiert.

: Bearbeitet durch User
von Walter T. (nicolas)


Lesenswert?

Daniel A. schrieb:
> könnte man
> ja meinen, das wird alles genullt.

Könnte man meinen, das erste Feld würde genullt.

von Rahul D. (rahul)


Lesenswert?

Niklas G. schrieb:
> Nein, die sind im C bzw. C++ Standard spezifiziert.

Mag sein. Aber sie sind nicht hardware-gebunden, was mit der o.g. 
falschen Aussage impliziert wird.
Wer außer dem (Pre-) Compiler kümmert sich denn um die Bitfelder bzw. 
übersetzt sie in Maschinencode?
Als Compiler-Erweiterung sehe ich Funktionen an, die in früheren 
Versionen nicht vorhanden waren.

von Niklas G. (erlkoenig) Benutzerseite


Lesenswert?

Rahul D. schrieb:
> Mag sein. Aber sie sind nicht hardware-gebunden, was mit der o.g.
> falschen Aussage impliziert wird.

Was heißt "hardware-gebunden"? Aller Code läuft auf Hardware...

Rahul D. schrieb:
> Als Compiler-Erweiterung sehe ich Funktionen an, die in früheren
> Versionen nicht vorhanden waren.

Also einen großen Teil der aktuellen C-Versionen? Da ist ja schon 
einiges hinzugekommen. Die meisten Leute verstehen unter 
Spracherweiterungen Features, welche nicht in der Spezifikation 
auftauchen und nur von einzelnen Compilern unterstützt werden.

von Rolf (rolf22)


Lesenswert?

Georg M. schrieb:

> Bitfelder stehen am Anfang des Programmierens. Ohne Bitfelder kann man
> den Mikrocontroller nicht programmieren.

Was dein Bild zeigt, ist überhaupt kein Bitfeld. Es ist ein 
Prozessorregister.

Ein Register oder eine Speicherzelle wird nicht dadurch zum Bitfeld, 
dass man die Bits in einer Dokumentation nummeriert und das Ganze dann 
"Bitfeld" nennt.

von Cyblord -. (cyblord)


Lesenswert?

Rahul D. schrieb:
> Mag sein. Aber sie sind nicht hardware-gebunden, was mit der o.g.
> falschen Aussage impliziert wird.

Missverständlich. Sie müssen korrekt benutzt werden. Anfänger treffen 
hier aber oft Annahmen die so nicht definiert sind.

Bitfelder sind eine Möglichkeit eine 1 Bit Info unter einem Namen zu 
speichern.

Bitfelder sind aber kein Ersatz für Bitoperationen auf Bytes, wenn ich 
am Ende das ganze Byte brauche.

von (prx) A. K. (prx)


Lesenswert?

Rahul D. schrieb:
> Wer außer dem (Pre-) Compiler kümmert sich denn um die Bitfelder bzw.
> übersetzt sie in Maschinencode?

Der Präprozessor, der mit dem "Pre-" vielleicht gemeint ist, 
interessiert sich in keinster Weise für Sprachkonstrukte von C, soweit 
diese nicht mit # anfangen. Also auch nicht für Bitfelder.

: Bearbeitet durch User
von Cyblord -. (cyblord)


Lesenswert?

Meistens ist es besser, auch 1 Bit Infos, einfach unter einem Byte zu 
speichern und auf Bitfelder zu verzichten. Es gibt so gut wie keinen 
Nachteil. Der gesparte Speicher dürfte heute keine Rolle mehr spielen.

Man kann die Variable ebenfalls benennen, man kann die in Arrays packen, 
in Strukturen. Ohne Probleme.
Einfach den Unsinn mit Bitfelder sparen. Vor allem als Anfänger.

von (prx) A. K. (prx)


Lesenswert?

Bei Bitfeldern, die Hardware abbilden, sollte man einrechnen, dass man 
die Kontrolle über die durchgeführten Zugriffe durch den Prozessor 
verliert. Bei Registern, die bei jedem Zugriff irgendwas auslösen, kann 
das fatal sein.

von Daniel A. (daniel-a)


Lesenswert?

Walter T. schrieb:
> Daniel A. schrieb:
>> könnte man
>> ja meinen, das wird alles genullt.
>
> Könnte man meinen, das erste Feld würde genullt.

Bei C werden, wenn man ein Feld eines Structs initialisiert, alle 
anderen mit 0 initialisiert. Padding muss aber nicht zwingend genullt 
werden, und - das wusste ich damals nicht - anonyme Bitfelder auch 
nicht.

von Obelix X. (obelix)


Lesenswert?

Cyblord -. schrieb:
> Meistens ist es besser, auch 1 Bit Infos, einfach unter einem Byte zu
> speichern und auf Bitfelder zu verzichten. Es gibt so gut wie keinen
> Nachteil. Der gesparte Speicher dürfte heute keine Rolle mehr spielen.

Man hat dann aber verloren, wenn die einzelnen Bits in einer Schleife 
verarbeitet werden sollen.

Rick M. schrieb:
> Es handelt sich hierbei nicht um die Ausgänge des uC, sondern um
> Ausgänge einer Regelung deren Status über den DL-Bus eingelesen wurden.

Ich verstehe den TO auch so, er bekommt irgendwoher einen uint16 und 
möchte die einzelnen Bits auswerten. Da hilft es wenig ihm den Tipp zu 
geben für die Bits komplette Bytes zu verwenden.

von Cyblord -. (cyblord)


Lesenswert?

Obelix X. schrieb:
> Cyblord -. schrieb:
>> Meistens ist es besser, auch 1 Bit Infos, einfach unter einem Byte zu
>> speichern und auf Bitfelder zu verzichten. Es gibt so gut wie keinen
>> Nachteil. Der gesparte Speicher dürfte heute keine Rolle mehr spielen.
>
> Man hat dann aber verloren, wenn die einzelnen Bits in einer Schleife
> verarbeitet werden sollen.

Wieso das? Du kannst so viele Variablen wie du willst in einem Array 
halten und in Schleifen verarbeiten.

von Daniel A. (daniel-a)


Lesenswert?

Obelix X. schrieb:
> Ich verstehe den TO auch so, er bekommt irgendwoher einen uint16 und
> möchte die einzelnen Bits auswerten. Da hilft es wenig ihm den Tipp zu
> geben für die Bits komplette Bytes zu verwenden.

Naja, "x & (1ul<<i)" usw. funktioniert auch bei uint16_t.

von Ob S. (Firma: 1984now) (observer)


Lesenswert?

Niklas G. schrieb:

> Genau richtig, insbesondere auch weil die AVR keinen Barrelshifter haben

Doch haben sie. Eigentlich alle außer den "klassischen" Tinys.

von Niklas G. (erlkoenig) Benutzerseite


Lesenswert?

Ob S. schrieb:
> Doch haben sie. Eigentlich alle außer den "klassischen" Tinys.

Mit welcher Instruktion nutzt man den?

: Bearbeitet durch User
von Arduino F. (Firma: Gast) (arduinof)


Lesenswert?

Ob S. schrieb:
> Doch haben sie. Eigentlich alle außer den "klassischen" Tinys.

Rick M. schrieb:
> (ATmega328)

Bist du dir sicher?

von (prx) A. K. (prx)


Lesenswert?

Ob S. schrieb:
> Doch haben sie. Eigentlich alle außer den "klassischen" Tinys.

Der mir bekannte Teil des AVR-Befehlssatzes kennt nur Shift/Rotate um 
eine Stelle.

: Bearbeitet durch User
von Ob S. (Firma: 1984now) (observer)


Lesenswert?

Niklas G. schrieb:
> Ob S. schrieb:
>> Doch haben sie. Eigentlich alle außer den "klassischen" Tinys.
>
> Mit welcher Instruktion nutzt man den?

Irgendwie wenig überraschend: Bei allen, die mit "mul" anfangen.

von Niklas G. (erlkoenig) Benutzerseite


Lesenswert?

Ob S. schrieb:
> Irgendwie wenig überraschend: Bei allen, die mit "mul" anfangen.

Wie würdest du damit folgende Funktionen implementieren?
1
uint8_t shiftLeft (uint8_t a, uint8_t b) {
2
  return a << b;
3
}
4
5
uint8_t shiftRight (uint8_t a, uint8_t b) {
6
  return a >> b;
7
}

von (prx) A. K. (prx)


Lesenswert?

Ob S. schrieb:
> Bei allen, die mit "mul" anfangen.

Das spricht einen Hardware-Multplizierer an, keinen Barrel-Shifter.

Hättest Du ein Beispiel für den Ersatz von x>>y durch eine einfache 
Multiplikation? Auch bei 1<<x ergibt sich nicht automatisch, dass 
Multiplikation und Potenzierung das Gleiche wären.

: Bearbeitet durch User
von Ob S. (Firma: 1984now) (observer)


Lesenswert?

(prx) A. K. schrieb:
> Ob S. schrieb:
>> Doch haben sie. Eigentlich alle außer den "klassischen" Tinys.
>
> Der mir bekannte Teil des AVR-Befehlssatzes kennt nur Shift/Rotate um
> eine Stelle.

Ja, das heißt aber nicht, dass es keinen Barrelshifter gäbe.

Man kann übrigens auch unter Verwendung der mul-Instruktion shiften...

OK, lohnt nur bei großen Shifts. So ungefähr ab 5 Bits, wenn ich das 
richtig in Erinnerung habe. Irgendwann hatte ich das mal analysiert, ist 
aber inzwischen mehr als ein Jahrzehnt her.

von Ob S. (Firma: 1984now) (observer)


Lesenswert?

(prx) A. K. schrieb:
> Ob S. schrieb:
>> Bei allen, die mit "mul" anfangen.
>
> Das spricht einen Hardware-Multplizierer an, keinen Barrel-Shifter.

Heilige Einfalt. Was glaubst du, was ein "Hardware-Multiplizierer" wohl 
im Kern sein mag...

von (prx) A. K. (prx)


Lesenswert?

Ob S. schrieb:
> Heilige Einfalt. Was glaubst du, was ein "Hardware-Multiplizierer" wohl
> im Kern sein mag...

Ich habe eine gewisse Vorstellung davon, wie ein kombinatorischer 
Multiplizierer funktioniert und ging bisher davon aus, dass das so 
implementiert sei. Ein Barrel-Shifter ist nicht dabei. Aber wenn dir 
andere Informationen vorliegen: immer raus damit.

: Bearbeitet durch User
von Georg M. (g_m)


Lesenswert?

Frank M. schrieb:
> Falls Du es immer noch nicht gemerkt hast: Es geht um die Verwendung von
> C-Bitfeldern und nicht allgemein um Bitfelder, an denen Du Dich
> aufhängst.

In der Überschrift steht "Bitfeld" und nicht "C-Bitfeld", und so habe 
ich es auch verstanden.

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


Lesenswert?

Georg M. schrieb:
> In der Überschrift steht .....

Und dann wars vorbei mit lesen.

von Cyblord -. (cyblord)


Lesenswert?

Georg M. schrieb:
> In der Überschrift steht "Bitfeld" und nicht "C-Bitfeld", und so habe
> ich es auch verstanden.

Im ersten Post ist aber direkt ein C-Bitfeld zu sehen.

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


Lesenswert?

Georg M. schrieb:
> "C-Bitfeld"

Cyblord -. schrieb:
> C-Bitfeld

Bitte!
C++, nicht C.









;-)

von Georg M. (g_m)


Lesenswert?

Cyblord -. schrieb:
> Im ersten Post ist aber direkt ein C-Bitfeld zu sehen.

Ja, Ok.
Ich dachte, man versucht es komplizierter als nötig zu machen, habe also 
alles falsch verstanden.

von Yalu X. (yalu) (Moderator)


Lesenswert?

Ob S. schrieb:
> Man kann übrigens auch unter Verwendung der mul-Instruktion shiften...
>
> OK, lohnt nur bei großen Shifts. So ungefähr ab 5 Bits, wenn ich das
> richtig in Erinnerung habe.

Ja, das geht mittels eines Zugriffs auf eine 8 Byte große Lookup-Tabelle
mit den Werten {0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80} und
einer Multiplikation. Das dürfte auf einem AVR sogar ab einem variablen
Shift um 2 schneller als die Variante mit Schleife sein. Noch schneller
geht es ohne MUL und ohne Schleife, wenn man dafür 8·256=2048 Bytes für
die Lookup-Tabelle opfert.

(prx) A. K. schrieb:
> Ob S. schrieb:
>> Heilige Einfalt. Was glaubst du, was ein "Hardware-Multiplizierer" wohl
>> im Kern sein mag...
>
> Ich habe eine gewisse Vorstellung davon, wie ein kombinatorischer
> Multiplizierer funktioniert und ging bisher davon aus, dass das so
> implementiert sei. Ein Barrel-Shifter ist nicht dabei.

Auch meine Vorstellungskraft reicht nicht aus, um in einem halbwegs
sinnvoll implementierten Multiplizierer (egal welcher Architektur) einen
Barrel-Shifter zu erkennen.

Aber vielleicht kann Ob. S. den Multiplizierer seiner Vorstellung
skizzieren und darin den Barrel-Shifter markieren.

: Bearbeitet durch Moderator
von Veit D. (devil-elec)


Lesenswert?

Hallo,

ich würde es anders lösen.

Eine 16 Bit Variable für die 13 Bits um die Zustände zu speichern.

enums, Namen für Bitnummer, praktisch dein struct Bitfeld nur in enums.

Funktion zum setzen der enum Bitnummer in der 16 Bit Variable.

Funktion zum löschen der enum Bitnummer in der 16 Bit Variable.

Eine Funktion zum iterieren über die 13 Bit Positionen für Portübergabe 
etc..

Wenn man in einer for Schleife viele/alle Bitpositionen vergleichen 
möchte, dann fängt man mit shiften nicht immer bei 0 an. Man führt die 
aktuelle Bitposition vom Shift für den kompletten Schleifendurchlauf 
mit. Damit muss je Schleifendurchlauf immer nur einmal weiter geschiftet 
werden.

Damit die Bitschubserei schneller geht, für den Fall das man die 
aktuelle Bitpos. in einer Schleife nicht mitführen kann, kann man sich 
eine weitere Funktion anlegen, Bitnummer als Eingangsparameter, damit 
springt man in ein Switch-Case und bekommt die Wertigkeit des Bits 
zurück.

: Bearbeitet durch User
von Falk B. (falk)


Lesenswert?

Man sollte vor irgendwelchen "Optimierungen" erstmal klären, wie gut und 
schnell es überhaupt nötig ist! Die Standardlösungen sind vermutlich für 
99% aller Anwendungen incl. des OP mehr als ausreichend!

https://www.mikrocontroller.net/articles/AVR-GCC-Codeoptimierung#Prinzipien_der_Optimierung
1
bool outputs[13];  // einfach, schnell, ein paar Bytes "verschwendet"
2
3
uint16_t outputs;  // Zugriff über Bitmasken, minimaler RAM-Bedarf, etwas mehr Programmspeicher und etwas "langsamer"
4
5
//Struct mit Bitfeld, wenig Ram, viel Programmspeicher, auch eher "langsam", viel Schreibarbeit
6
7
struct Ausgaenge        // jeweils 1 Bit fuer Speicherung der Zustaende der 
8
{
9
        uint16_t A1:1;
10
        uint16_t A2:1;
11
        uint16_t A3:1;
12
        uint16_t A4:1;
13
        uint16_t A5:1;
14
        uint16_t A6:1;
15
        uint16_t A7:1;
16
        uint16_t A8:1;
17
        uint16_t A9:1;
18
        uint16_t A10:1;
19
        uint16_t A11:1;
20
        uint16_t A12:1;
21
        uint16_t A13:1;
22
} Ausgang;
23
24
for (uint8_t i=1; i<=13; i++)
25
    {
26
        bool tmp;
27
        Serial.print("A");
28
        Serial.print(i);
29
        Serial.print(": ");
30
        switch(i) {
31
          case  1: tmp = Ausgang.A1; break;
32
          case  2: tmp = Ausgang.A2; break;
33
          case  3: tmp = Ausgang.A3; break;
34
          case  4: tmp = Ausgang.A4; break;
35
          case  5: tmp = Ausgang.A5; break;
36
          case  6: tmp = Ausgang.A6; break;
37
          case  7: tmp = Ausgang.A7; break;
38
          case  8: tmp = Ausgang.A8; break;
39
          case  9: tmp = Ausgang.A9; break;
40
          case 10: tmp = Ausgang.A10; break;
41
          case 11: tmp = Ausgang.A11; break;
42
          case 12: tmp = Ausgang.A12; break;
43
          case 13: tmp = Ausgang.A13; break;
44
       }  
45
       Serial.println(tmp);
46
     }

von Ob S. (Firma: 1984now) (observer)


Lesenswert?

Yalu X. schrieb:

> Auch meine Vorstellungskraft reicht nicht aus, um in einem halbwegs
> sinnvoll implementierten Multiplizierer (egal welcher Architektur) einen
> Barrel-Shifter zu erkennen.

Nunja. Die Tatsache, dass die mul*-Instruktionen der AVR8 zwei und nicht 
nur einen Takt kosten, läßt stark vermuten, dass hier eine Kombination 
aus einem Barrel-Shifter und kombinatorischer Logik verwendet wurde.

Wär's rein kombinatorisch, sollte nämlich schlicht ein Takt reichen.

Aber das ist natürlich nur ein Indiz, kein wirklicher Beweis. Insofern 
gebe ich dir Recht.

Für wirkliche Beweise müßte man an Infos rankommen, die MC kaum 
freiwillig rausrücken dürfte.

von Georg M. (g_m)


Lesenswert?

Arduino F. schrieb:
> Bitte!
> C++, nicht C.

Übrigens, ist C++ immer die bessere Wahl?

Ich denke, es ist schon ein Unterschied, ob man einen kleinen 
Mikrocontroller programmiert (größtenteils Hardware Programmierung) oder 
ein Office-Paket.

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


Lesenswert?

Georg M. schrieb:
> Übrigens, ist C++ immer die bessere Wahl?

Ich persönlich: Denke schon!

Georg M. schrieb:
> Ich denke, es ist schon ein Unterschied, ob man einen kleinen
> Mikrocontroller programmiert (größtenteils Hardware Programmierung) oder
> ein Office-Paket.
Sicherlich!

Ich sehe keine Nachteile für C++ auf µC.

von Alexander (alecxs)


Lesenswert?

Die eigentliche Frage war doch nur, ob es möglich ist zur Laufzeit 
Variablenbezeichner dynamisch zu konstruieren.

von Cyblord -. (cyblord)


Lesenswert?

Alexander schrieb:
> Die eigentliche Frage war doch nur, ob es möglich ist zur Laufzeit
> Variablenbezeichner dynamisch zu konstruieren.

Ja und darauf gibt es zwei Antworten:

1.) Nein, nicht mit solchen Bitfeldern.
2.) Die gesamte Aufgabe löst man anders.

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


Lesenswert?

Alexander schrieb:
> Die eigentliche Frage war doch nur, ob es möglich ist zur Laufzeit
> Variablenbezeichner dynamisch zu konstruieren.

Ein klares nein!
Das können nur Interpretersprachen.

Bei Kompilersprachen gehen die Variabelenbezeichner (meist?) während der 
Übersetzung verloren.

Beitrag #7742415 wurde vom Autor gelöscht.
von Yalu X. (yalu) (Moderator)


Lesenswert?

Arduino F. schrieb:
> Alexander schrieb:
>> Die eigentliche Frage war doch nur, ob es möglich ist zur Laufzeit
>> Variablenbezeichner dynamisch zu konstruieren.
>
> Ein klares nein!
> Das können nur Interpretersprachen.

Das nennt sich "Reflection" und ist nicht auf Interpretersprachen
beschränkt. Beispiele für kompilierte Sprachen mit Reflection sind Java,
C# (und andere .NET-Sprachen), Go, Object Pascal, Objective C und
natürlich Common Lisp.

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


Lesenswert?

Yalu X. schrieb:
> Java,
> C# (und andere .NET-Sprachen), Go, Object Pascal, Objective C und
> natürlich Common Lisp.

Haben wir hier nicht.

von Bruno V. (bruno_v)


Lesenswert?

Georg M. schrieb:
> Ich denke, es ist schon ein Unterschied, ob man einen kleinen
> Mikrocontroller programmiert (größtenteils Hardware Programmierung)

Für Bitschubsereien, Konstanten und alles was vorab errechnet werden 
kann ist man bei C++ besser aufgehoben. In C teilen sich Präprozessor 
und Compiler die Arbeit nicht immer optimal, auch wenn C kontinuierlich 
nachzieht.

Allerdings sind unsere C++-Projekte meist aus dem Ruder gelaufen, weil 
es unüberschaubare Möglichkeiten gibt. Und da es uns nicht auf ein paar 
kB ankommt, sind wir wieder bei C.  (Ja, man kann Programmierer zähmen 
und sogar einen Klammerstil vorgeben ;-).

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


Lesenswert?

Bruno V. schrieb:
> weil es unüberschaubare Möglichkeiten gibt
Ja, die Vielseitigkeit kann einen schon beindrucken.

von Obelix X. (obelix)


Lesenswert?

Daniel A. schrieb:
> Obelix X. schrieb:
>> Ich verstehe den TO auch so, er bekommt irgendwoher einen uint16 und
>> möchte die einzelnen Bits auswerten. Da hilft es wenig ihm den Tipp zu
>> geben für die Bits komplette Bytes zu verwenden.
>
> Naja, "x & (1ul<<i)" usw. funktioniert auch bei uint16_t.

Hast du den Beitrag gelesen, auf den ich mich beziehe?

von Georg M. (g_m)


Lesenswert?

Nachdem ich nun erfahren habe, dass Bitfeld nicht nur ein Begriff ist, 
sondern dass es unter diesem Ausdruck auch ein konkretes Sprachelement, 
eine Struktur gibt, verstehe ich immer noch nicht den praktischen Sinn, 
die Nützlichkeit.

von Niklas G. (erlkoenig) Benutzerseite


Lesenswert?

Georg M. schrieb:
> verstehe ich immer noch nicht den praktischen Sinn, die Nützlichkeit.

Man kann Daten mit weniger als 8bit platzsparend unterbringen und 
dennoch recht komfortabel zugreifen, meistens auf Kosten der Laufzeit.

von Walter T. (nicolas)


Lesenswert?

Georg M. schrieb:
> verstehe ich immer noch nicht den praktischen Sinn,
> die Nützlichkeit.

Walter T. schrieb:
> Der sinnvolle Anwendungsbereich von Bitfeldern ist sehr begrenzt.

Bitfelder sind dann sinnvoll, wenn Speicherplatz wirklich gespart werden 
muss.

Da die Variablen in Funktionen ohnehin nur sehr kurz leben, in 
Funktionen also fast nie.

Wenn man Daten mehr oder weniger dauerhaft speichern will, z.B. in einem 
EEPROM oder globale Flags, sind Bitfelder teilweise sinnvoll.

von Cyblord -. (cyblord)


Lesenswert?

Walter T. schrieb:
> Wenn man Daten mehr oder weniger dauerhaft speichern will, z.B. in einem
> EEPROM oder globale Flags, sind Bitfelder teilweise sinnvoll.

Aber genau hier lauert das Problem. Die Repräsentation von Bitfeldern im 
Speicher ist nicht garantiert.

von Daniel A. (daniel-a)


Lesenswert?

Georg M. schrieb:
> verstehe ich immer noch nicht den praktischen Sinn,
> die Nützlichkeit.

Wenn du keine ganzen Bytes brauchst, und du willst unbedingt etwas platz 
sparen, kannst du damit den Compiler Zeugs zusammenfassen lassen, und 
musst das nicht selbst manuell mit Bitshifts machen.

Ich hatte das z.B. mal verwendet, um bei einer Streaming UTF-8 
Validierungsfunktion, den Zustand in nur 1 Byte (bzw. sogar nur 7 Bits, 
wird aber aufgerundet), zu packen:
https://github.com/Daniel-Abrecht/ml666/blob/41d337313e4178bd2bbd882d6f7fa62c7cba44a6/include/ml666/utils.h#L62-L77
https://github.com/Daniel-Abrecht/ml666/blob/41d337313e4178bd2bbd882d6f7fa62c7cba44a6/src/utils.c#L341-L413
Ist sicher nicht besonders Effizient, und ich weiss nicht mehr, warum 
ich das in 1 Byte packen wollte. Ich glaube ich wollte das irgendwo in 
ein Struct Reinquetschen, wo gerade noch etwas Platz übrig war 
(Padding), und wo ich dieses klein halten wollte, weil es sehr oft 
verwendet worden wäre.

: Bearbeitet durch User
von Walter T. (nicolas)


Lesenswert?

Cyblord -. schrieb:
> Aber genau hier lauert das Problem. Die Repräsentation von Bitfeldern im
> Speicher ist nicht garantiert.

Ist in den meisten Fällen nicht schlimm. Das EEPROM wird meist vom 
selben Programm gelesen wie vorher geschrieben.

Bei Dateien ist die Serialisierung sowieso komplizierter als eine 
einzelne Variable oder so zu dumpen.

von Dergute W. (derguteweka)


Lesenswert?

Cyblord -. schrieb:
> Walter T. schrieb:
>> Wenn man Daten mehr oder weniger dauerhaft speichern will, z.B. in einem
>> EEPROM oder globale Flags, sind Bitfelder teilweise sinnvoll.
>
> Aber genau hier lauert das Problem. Die Repräsentation von Bitfeldern im
> Speicher ist nicht garantiert.

Nein, bei den beiden geschilderten Problemstellungen ist das kein 
Problem. Das Problem faengt erst da an, wenn irgendwer auf die geniale 
Idee kommt, irgendwelche Register, hinter denen sich HW verbirgt, mit 
sowas "schoener" machen zu wollen. Wo halt die Reihenfolge der Bitfelder 
von LSB zu MSB oder umgekehrt nicht mehr wurst ist.

Gruss
WK

von Rahul D. (rahul)


Lesenswert?

Niklas G. schrieb:
> Was heißt "hardware-gebunden"? Aller Code läuft auf Hardware...

Guck dir mal den 8051 an. Der hat Bitfelder bzw. Befehle, um Bits in 
Register direkt anzusprechen.

(prx) A. K. schrieb:
> Der Präprozessor, der mit dem "Pre-" vielleicht gemeint ist,
> interessiert sich in keinster Weise für Sprachkonstrukte von C, soweit
> diese nicht mit # anfangen. Also auch nicht für Bitfelder.

Deswewgen auch in Klammern.

Cyblord -. schrieb:
> Bitfelder sind aber kein Ersatz für Bitoperationen auf Bytes, wenn ich
> am Ende das ganze Byte brauche.

Genau. Was der Compiler daraus macht, könnte man auch von Hand 
erledigen.
Das ist eine Compiler-Erweiterung, die Komfort schafft.
Wo die definiert ist und wer die umsetzt, ist für Anfänger (und viele 
andere) ziemlich egal.
Man sollte schon wissen, was passiert. Es ist ja keine Magie.

von Daniel A. (daniel-a)


Lesenswert?

Naja, bei Registern sollte das ja kein Problem sein. Die sind sowieso 
Platformabhängig, da macht es also nichts, sich auf das zu Verlassen, 
was der Compier da an verhalten spezifiziert (zumindest sofern er das 
tut). Dann muss man halt wissen, wie der das handhabt, genauso wie man 
auch wissen muss, was die Register tun.

Ein grösseres Problem ist, wenn manche meinen, sie könnten die Bitfelder 
Platformunabhängig zum Dekodieren von Protokollen nutzen, und es dann 
halt auf einer anderen Plattform nicht mehr geht, weil die da halt 
anders angeordnet wurden.

Rahul D. schrieb:
> Das ist eine Compiler-Erweiterung, die Komfort schafft.

Nein, das ist keine Compiler-Erweiterung. Bitfelder sind teil des C 
Standards, es sind nur gewisse Aspekte davon IB.

von Rahul D. (rahul)


Lesenswert?

Daniel A. schrieb:
> Ein grösseres Problem ist, wenn manche meinen, sie könnten die Bitfelder
> Platformunabhängig zum Dekodieren von Protokollen nutzen, und es dann
> halt auf einer anderen Plattform nicht mehr geht, weil die da halt
> anders angeordnet wurden.
Protokolle sollten schon eindeutig und nicht von irgendwelchen Endians 
o. dergl. abhängig sein.
Und wenn, dann ist die Umsetzung das Problem des Entwicklers / 
Programmierers (m/w/d).
Etwas Grundwissen sollte man schon haben oder sich erarbeiten.

> Rahul D. schrieb:
>> Das ist eine Compiler-Erweiterung, die Komfort schafft.
>
> Nein, das ist keine Compiler-Erweiterung. Bitfelder sind teil des C
> Standards, es sind nur gewisse Aspekte davon IB.

Der Ur-C-Compiler hatte bzw. der -Standard kannte diese Funktion nicht, 
also ist es eine Erweiterung. Die Bitfelder kamen doch erst in "letzter" 
Zeit dazu (ca. in den letzten 20 Jahren - bei einer Programmiersprache, 
die ca. 50 Jahre alt ist...).
Dass der Standard mit der Zeit erweitert wird, ist ja nichts negatives.

von Niklas G. (erlkoenig) Benutzerseite


Lesenswert?

Rahul D. schrieb:
> Guck dir mal den 8051 an. Der hat Bitfelder bzw. Befehle, um Bits in
> Register direkt anzusprechen.

Das können viele andere Architekturen auch.

Rahul D. schrieb:
> Genau. Was der Compiler daraus macht, könnte man auch von Hand erledigen

Das gilt aber für viele Dinge in C. Das (a << b) lässt sich auf 
Plattformen wie AVR wie gesagt überhaupt nicht direkt umsetzen sondern 
braucht auch eine vom Compiler implementierte Hilfsfunktion. Sind 
Bitshifts jetzt auch eine "Compiler-Erweiterung"? Wie ist es mit 
16bit-Multiplikation, Division, usw.?

Rahul D. schrieb:
> Der Ur-C-Compiler hatte bzw. der -Standard kannte diese Funktion nicht,
> also ist es eine Erweiterung.

Aber eine Erweiterung durch den Standard, nicht einen Compiler. Somit 
ist der Begriff "Compiler-Erweiterung" ziemlich unpassend. Insbesondere 
auch weil dann fast alle Features die man heute so nutzt eine 
"Compiler-Erweiterung" wären, z.B. die "+=" Operatoren, Parameter-Typen, 
void-FUnktionen usw...

: Bearbeitet durch User
von Pilot P. (klatschnass)


Lesenswert?

Niklas G. schrieb:
> Das gilt aber für viele Dinge in C. Das (a << b) lässt sich auf
> Plattformen wie AVR wie gesagt überhaupt nicht direkt umsetzen sondern
> braucht auch eine vom Compiler implementierte Hilfsfunktion.
Dann schau dir mal die Befehle LSL, LSR, ROL, ROR, ASR im 
AVR-Befehlssatz an.

von Niklas G. (erlkoenig) Benutzerseite


Lesenswert?

Pilot P. schrieb:
> Dann schau dir mal die Befehle LSL, LSR, ROL, ROR, ASR im
> AVR-Befehlssatz an.

Klär mich gerne auf wie man damit direkt (in 1 Instruktion und 1  Takt) 
ein "a << b" umsetzt wenn "b" erst zur Laufzeit bekannt ist.

von Walter T. (nicolas)


Lesenswert?

Wird jetzt gerade darüber diskutiert, dass 1 Befehl in einer Hochsprache 
nicht 1 Befehl in Assembler und auch nicht 1 Takt in der Ausführung 
entspricht?

von Niklas G. (erlkoenig) Benutzerseite


Lesenswert?

Walter T. schrieb:
> Wird jetzt gerade darüber diskutiert, dass 1 Befehl in einer
> Hochsprache
> nicht 1 Befehl in Assembler und auch nicht 1 Takt in der Ausführung
> entspricht?

Ja, nach Rahuls Logik sind Sprachelemente wie C-Bitfields die nicht 
direkt einzelne Assemblerbefehle übersetzt werden können 
"Compiler-Erweiterungen". Daher müssen beim AVR auch variable Bitshifts, 
16bit-Multiplikationen und Zugriffe auf lokale Stack-Variablen 
(erfordern Adressberechnungen) "Compiler-Erweiterungen" sein.

von Cyblord -. (cyblord)


Lesenswert?

Die Diskussion geht jetzt völlig in die falsche Richtung. Es geht doch 
nicht um die Implementation von Sprachelementen. Sondern um die mögliche 
Repräsentation von Bitfeldern im Speicher.

: Bearbeitet durch User
von Walter T. (nicolas)


Lesenswert?

Niklas G. schrieb:
> Rahuls Logik

Für feststehende Begriffe eigene Bedeutungen unterzuschieben ist keine 
Logik. Also braucht man sich damit auch nicht zu beschäftigen.

Mit Leuten mit eigener Semantik ist genauso wie mit einer rauchenden 
Raupe sinnvoll zu diskutieren.

: Bearbeitet durch User
von Heinz B. (Firma: Privat) (hbrill)


Lesenswert?

Niklas G. schrieb:
> Man kann Daten mit weniger als 8bit platzsparend unterbringen und
> dennoch recht komfortabel zugreifen, meistens auf Kosten der Laufzeit.

Ich meine, die Wertigkeit eines Bytes bleibt doch immer die gleiche,
ob jetzt nur 3 Bit oder 8 Bit relevant sind. Platz für 8 Bit ist doch
immer gegben. Also so wie auch Integervariablen auf einem 32Bit System
in 4 Bytes gehalten werden.

Gibt es denn noch was kleineres als 1 Bit ?
Dachte immer, das wäre die kleinste Einheit, so wie ich das mal
vor über 35 Jahren gelernt habe :
1
1 Byte = 8 Bit
2
1 KB = 1024 Bytes
3
1 MB = 1024 KB
4
usw.

Jedenfalls kenne ich mal keine Sprache, die < 1 Bit kann. 
Speichertechnisch,
wenn auf Datenträger geschrieben wird, sogar nur byteweise.

Klär mich doch mal auf.

: Bearbeitet durch User
von Cyblord -. (cyblord)


Lesenswert?

Heinz B. schrieb:
> Ich meine

Ich meine du hast den Punkt irgendwie nicht verstanden.

von Rahul D. (rahul)


Lesenswert?

Niklas G. schrieb:
> Aber eine Erweiterung durch den Standard, nicht einen Compiler. Somit
> ist der Begriff "Compiler-Erweiterung" ziemlich unpassend. Insbesondere
> auch weil dann fast alle Features die man heute so nutzt eine
> "Compiler-Erweiterung" wären, z.B. die "+=" Operatoren, Parameter-Typen,
> void-FUnktionen usw...

Habe ich mich auf einen speziellenn Compiler bezogen?
Für die Kortinthenkacker:
Bitfelder sind eine Erweiterung von C-Compilern (im Vergleich zu 
früheren Versionen, die dem Standard hinzugefügt wurde).
Zufrieden?

Ob andere Programmiersprachen Bitfelder unterstüzen, weiß ich nicht 
(interessiert hier ja auch gar nicht).

von Niklas G. (erlkoenig) Benutzerseite


Lesenswert?

Heinz B. schrieb:
> Jedenfalls kenne ich mal keine Sprache, die < 1 Bit kann

Hä? Davon habe ich überhaupt nicht geredet. Mit Bitfields kann man z.B. 
eine 3bit Variable, eine 4bit Variable und eine 1bit Variable in einem 
Byte unterbringen. Genau das was hier von Anfang an diskutiert wurde. 
Ich habe nur noch mal auf den Punkt gebracht, dass der Sinn von 
C-Bitfields diese Speicherersparnis ist und nichts anderes.

von Niklas G. (erlkoenig) Benutzerseite


Lesenswert?

Rahul D. schrieb:
> Bitfelder sind eine Erweiterung von C-Compilern (im Vergleich zu
> früheren Versionen, die dem Standard hinzugefügt wurde).
> Zufrieden?

Sind dann der "+=" Operator, void-Funktionen, Parameter mit Typangabe 
auch Erweiterungen für dich?

von Rahul D. (rahul)


Lesenswert?

Niklas G. schrieb:
> Sind dann der "+=" Operator, void-Funktionen, Parameter mit Typangabe
> auch Erweiterungen für dich?

Nur mal so zur "Logik": Wenn es etwas in einem Standard bisher nicht 
gab, das aber im Standard definiert wurde: Wie sollte man das dann 
nennen?
Wurde die Programmiersprache dann erweitert?
Wer kümmert sich dann um die Umsetzung dieser Erweiterung im 
Maschinencode?

von Niklas G. (erlkoenig) Benutzerseite


Lesenswert?

Rahul D. schrieb:
> Wie sollte man das dann nennen?

Sprachelement/Feature. Anfangs kann man noch "neu" dazu schreiben, aber 
"neu" sind C-Bitfields sicher nicht mehr.

Rahul D. schrieb:
> Wer kümmert sich dann um die Umsetzung dieser Erweiterung im
> Maschinencode?

Weil alle Sprachfeatures von Compilern umgesetzt werden, auch die die 
von Anfang an in der Sprache waren, ist es unlogisch nur bei "neuen" 
Features ein "Compiler" voranzustellen. Logischer wäre es, den Ausdruck 
"Compiler-Erweiterung" nur für Features zu nutzen, die nur von einem 
bestimmten Compiler, aber nicht vom Standard unterstützt werden.

von Daniel A. (daniel-a)


Lesenswert?

Rahul D. schrieb:
> Wenn es etwas in einem Standard bisher nicht
> gab, das aber im Standard definiert wurde: Wie sollte man das dann
> nennen?

Entweder es gibt etwas im Standard, oder eben nicht. Wenn man es genauer 
wissen will, kann man angeben, welchen Standard man meint.
In C89 z.B. sind bitfields schon drin, in C23 sind sie immer noch. Und 
ältere Standards gibt es nicht wirklich (Ausser man sieht K&R als 
(quasi-)Standard?).

Übrigens, jeder C Standard sagt immer, die älteren sind damit obsolete & 
ersetzt. Der C Standard ist also immer der neuste.

Ich persönlich bevorzuge aber C11/C17 gegenüber C23.

von (prx) A. K. (prx)


Lesenswert?

Niklas G. schrieb:
> Sind dann der "+=" Operator [...] auch Erweiterungen für dich?

Die waren von Anfang an drin, zunächst jedoch mit abweichender Syntax.

von Yalu X. (yalu) (Moderator)


Lesenswert?

Rahul D. schrieb:
> Die Bitfelder kamen doch erst in "letzter" Zeit dazu (ca. in den
> letzten 20 Jahren - bei einer Programmiersprache, die ca. 50 Jahre alt
> ist...).

Da hast du dich etwas verschätzt. Die Bitfelder gab es zwar nicht von
Anfang an, wurden bereits 1978 (also vor 46 Jahren) im K&R-Buch
beschrieben.

Es gab sie somit schon mindestens 11 Jahre vor dem ersten ANSI- und 12
Jahre vor dem ersten ISO-Standard.

von Dergute W. (derguteweka)


Lesenswert?

Moin,

Yalu X. schrieb:
> Es gab sie somit schon mindestens 11 Jahre vor dem ersten ANSI- und 12
> Jahre vor dem ersten ISO-Standard.

Und ich bin mir auch ziemlich sicher, dass schon in einer 
einsemestrigen, kombinierten Pascal/C-Vorlesung, die ich weit zurueck im 
letzten Jahrtausend besuchte, eindringlich davor gewarnt wurde, die zu 
verwenden, weil nicht definiert ist, in welcher Reihenfolge/Richtung der 
Compiler die verbaut...

Gruss
WK

von Heinz B. (Firma: Privat) (hbrill)


Lesenswert?

Das ist ja mein Defizit :
Was ist denn eine 1Bit oder 3Bit Variable ?
Jedenfalls hatte ich im PC-Bereich noch nie was davon gehört.
Mag es vl. im Mikroprozessorbereich geben.
Selbst bei WINDOWS kann man nur byteweise Speicher allocieren.
Allocmem verlangt da die Anzahl Bytes nicht die Anzahl Bits.
Oder schreib mal hier, wie du mit der API 3 Bit Speicher
allocierst.

von Rahul D. (rahul)


Lesenswert?

Yalu X. schrieb:
> Da hast du dich etwas verschätzt. Die Bitfelder gab es zwar nicht von
> Anfang an, wurden bereits 1978 (also vor 46 Jahren) im K&R-Buch
> beschrieben.
>
> Es gab sie somit schon mindestens 11 Jahre vor dem ersten ANSI- und 12
> Jahre vor dem ersten ISO-Standard.

Ok. Mit C programmiere ich erst seit 2005. Danach wurden die Bitfelder 
populär (zumindest gab es zu der Zeit und danach hier im Forum diverse 
Anfragen zu dem Thema - soweit ich mich richtig erinnere).

von Walter T. (nicolas)


Lesenswert?

Heinz B. schrieb:
> Selbst bei WINDOWS kann man nur byteweise Speicher allocieren.

Warte mal ab, bis Du von alignment und padding gehört hast.

von Bruno V. (bruno_v)


Lesenswert?

Rahul D. schrieb:
> Mit C programmiere ich erst seit 2005. Danach wurden die Bitfelder
> populär

Das bezweifle ich. Gerade in den 20 Jahren davor war Portabilität im 
embedded-Bereich weniger wichtig. Es gab noch kein Internet, wo man 
seinen Kram für ganz andere Prozessorfamilien bereitgestellt hat.

Du hast einen neuen Prozessor, ein oder ein paar Dutzend Projekte damit 
und entweder vom Compilerhersteller oder nach ein paar Stunden sämtliche 
Register-Elemente zugreifbar in der Form Uart.Flags.OERR als einzelnes 
Bit. Oder als 5Bit breites Register von B2..B6 um schreiben zu können: 
Uart.BRR.PRE=31.

Davor kam eine Stunde blättern im Compilerhandbuch nach Reihenfolge, 
padding, etc. So wie Du auch zu Beginn wissen willst, was (-5%3) ergibt 
oder sizeof(int).

von Rahul D. (rahul)


Lesenswert?

Bruno V. schrieb:
> Das bezweifle ich.
Tu, was du willst. Es sind meine Erfahrungen und Erinnerungen.

> Gerade in den 20 Jahren davor war Portabilität im
> embedded-Bereich weniger wichtig. Es gab noch kein Internet, wo man
> seinen Kram für ganz andere Prozessorfamilien bereitgestellt hat.
Damals habe ich mir teilweise noch (AVR-)Datenblätter ausgedruckt.

Einen Kommentar zum Rest erspare ich mir, da ich den Sinn deines 
Geschrieben nicht verstehe.

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.