Warum gibt es kein Bit-Array in C?

OP #3196792
Lesenswert?

Hallo,
ja ich denke die Frage ist eindeutig ?
Ich muss in meinem MCU ca. 4x70 Bit abspeichern.
Wenn ich dafür Char[x] verwende, dann ist das doch 
Speicherplatzverschwendung.
Also Bit Varname [70]  wäre super, geht nur bei meinem HI-TECH C (PIC) 
nicht.
Wie sieht es in der AVR Welt aus ?
Gruß Dirk
Gast #3196802
Lesenswert?

Dirk F. schrieb:
> Hallo,
> ja ich denke die Frage ist eindeutig ?
> Ich muss in meinem MCU ca. 4x70 Bit abspeichern.
> Wenn ich dafür Char[x] verwende, dann ist das doch
> Speicherplatzverschwendung.
> Also Bit Varname [70]  wäre super, geht nur bei meinem HI-TECH C (PIC)
> nicht.
> Wie sieht es in der AVR Welt aus ?
> Gruß Dirk

Warum? Weil C keine ernstzunehmende Programmiersprache ist und auch 
nicht als solche konzipiert wurde. Nichts weiter als ein Treppenwitz der 
EDV-Geschichte. Verwende Assembler, dann musst Du Dich nicht mehr mit 
den Unzulänglichkeiten und Fehlern der sog. "Compiler" herumplagen.
#3196803
Lesenswert?

4 Bit = 1 Nibble = 1/2 Byte

Klingt brauchbar. Und wenn man sich mit Bitmanipulation ein wenig 
auskennt, ist das alles kein Thema. Und für einen bequemen Zugriff gibt 
es Funktionen.

char bitfeld [35];
1
set_bit(char *data, int bitnummer) {
2
    int index, mask;
3
    
4
    index = bitnummer / 8;
5
    mask = 1 << (bitnummer % 8);
6
    data[index] |= mask;
7
}

Löschen und Abfragen geht genau so
#3196807
Lesenswert?

@frickelsprachenhasser (Gast)

>EDV-Geschichte. Verwende Assembler, dann musst Du Dich nicht mehr mit
>den Unzulänglichkeiten und Fehlern der sog. "Compiler" herumplagen.

Aha. Verwende einen Faustkeil, weil das iPad noch nicht Gedanken lesen 
kann und man es noch mit den Fingern bedienen muss.
Gast #3196809
Lesenswert?

> Wenn ich dafür Char[x] verwende, dann ist das doch
> Speicherplatzverschwendung.

Wieso das denn, braucht genau (n +7) /8 unsigned char, noch dichter 
gepackt gehts nicht auf den üblichen binären Plattformen. Nur die 
Zugriffe sind suboptimal, das kann man sich mit eine paar Makros aber 
stark vereinfachen.
Gast #3196824
Lesenswert?

Dirk F. schrieb:
> C ist für mich die ideale Programmiersprache für MCUs.

Und genau weil genügend Leute aus der Anfangszeit der PC- und µC-Welt 
dies von sich behaupten, ist dieses Gefrickel aus den 80er Jahren des 
vorigen Jahrhunderts immer noch Standard in der µC-Welt.
#3196841
Lesenswert?

Georg G. schrieb:
> K&R, The C Programming Language, 1978, Seite 136, Bit Fields.
>
> Geht simpel und bequem.

Dann kannst du aber nicht mehr mit Arrays arbeiten. Die Struktur hat 
dann 70 Member, die jeweils ein Bit gross sind und auf die alle manuell 
zugegriffen werden muss. Nicht gerade praktikabel.

Oder meinst du was anderes? Mach mal ein Beispiel.
Moderator #3196845
Lesenswert?

frickelsprachenhasser schrieb:
> Verwende Assembler, dann musst Du Dich nicht mehr mit
> den Unzulänglichkeiten und Fehlern der sog. "Compiler" herumplagen.

Ach, unser alter Egbert mal wieder :)

Und welcher Assemblersprache unterstützt Bit-Arrays, wenn ich fragen
darf?

Bit-Arrays bzw. gepackte Bool-Arrays gibt es bspw. in C++ (vector<bool>)
und in Pascal. Aber in Assembler habe ich noch nicht einmal gewöhnliche
Arrays gesehen, geschweige denn Bit-Arrays.

Georg G. schrieb:
> K&R, The C Programming Language, 1978, Seite 136, Bit Fields.

Bitfelder sind leider wieder etwas anderes: Zum einen ist deren Größe
begrenzt, zum anderen sind es keine Arrays, da man darauf nicht per
Index zugreifen kann.
#3196846
Lesenswert?

Bitfelder und Bitarrays sind zwei recht verschiedene Paar Stiefel.

C hat in seinem Sprachsansatz praktisch nur Datentypen vorgesehen, die 
sich ziemlich direkt auf die Maschinen der Entstehungszeit abbilden 
liessen. Bitadressierung war nicht darunter. In dieser Tradition ging es 
auch später weiter.

Und da kann nun drüber meckern oder glücklich sein, und trollen bis der 
Arzt kommt, aber ändern wird sich das wohl nicht mehr. Wen das stört, 
der kann jederzeit die Sprache wechseln. Bereits bei C++ hat er die 
Freiheit, sich das synaktisch wie gewünscht zu implementieren.
#3196850
Lesenswert?

Yalu X. schrieb:
> Aber in Assembler habe ich noch nicht einmal gewöhnliche
> Arrays gesehen, geschweige denn Bit-Arrays.

Bei den PIC18 gibt es Tabellen, auf die fast wie ein Array zugegriffen 
werden kann (Keine Ahnung wie das genau funktioniert, habs noch nie 
selbst gemacht). Die PIC18 wurden aber auch speziell für C entwickelt, 
deshalb ist sowas wohl implementiert worden.
#3196851
Lesenswert?

PS: Wer unbedingt C mit syntaktisch auch als Arrays dargestellten 
Bitarrays braucht, der kann sich mal bei den µCs auf Basis der 
Cortex-M3/M4 Cores umsehen, Zu deren eher selten genutzen Features 
gehört nämlich eine Einzelbitadressierung des RAMs. Siehe [[ARM 
Bitbanding]].
Gast #3196864
Lesenswert?

Hi Dirk,

Bitfields sehen so aus:
1
....
2

3
struct 
4
__attribute__((packed)) // oder was Dein Compiler hier möchte
5
{
6
uint8_t bit0 : 1;
7
uint8_t bit1 : 1;
8
uint8_t bit2 : 1;
9
uint8_t bit3 : 1;
10
uint8_t bit4 : 1;
11
uint8_t bit5 : 1;
12
uint8_t bit6 : 1;
13
uint8_t bit7 : 1;
14
} bytes[10];
15

16
int main (void)
17
{
18

19
    bytes[0].bit0 = 0;
20
    bytes[5].bit5 = 1;
21

22
    ....
23
}

Allerdings kann man sie nicht aĺs Array verwenden (im Beispiel oben: bit 
kann kein Array sein), da Bitfields halt nicht direkt adressierbar sind.
Außerdem schaden sie der Performance, da man sich erst das richtige Bit 
rausfriemeln muß. Deshalb werden Daten auch oftmals nicht so dicht wie 
möglich gepackt sondern an Adressen gelegt, auf die möglichst effizient 
zugegriffen werden kann (z.B. ganzzahlig durch 4, 8, .... teilbar);
das macht dann structs auch größer, als sie sein sollten (und dieses
Verhalten verhindert man durch die explizite Kompilerdirektive 
"packed").
Letztere ist allerdings nicht in C spezifiziert und variiert daher
von Kompiler zu Kompiler.

Viele Grüße
  flipsi
Gast #3196887
Lesenswert?

Achso,
mit Macros kann man sich übrigens ev. auch die Bit-Array-Funktion bauen,
aber das sieht wahrlich syntaktisch nicht schön aus (bezogen auf meinen 
vorherigen Code) (folgende Version eignet sich nicht für Schleifen):
1
#define BIT(y,x) bytes[y].bit##x
2
// Achtung, ## (concat) ist ev. nicht in allen Kompilern vorhanden,
3
// und heißt bei Dir anders
4
int main (void)
5
{
6
....
7
    BIT(3,4) = 1;
8
....
9
}

Falls notwendig, kann man aber auch ein Macro formulieren, das für
Schleifen geeignet ist (oder einfacher ein SetBit Makro und ein GetBit
Makro).

Viele Grüße & viel Erfolg
  flipsi
#3196913
Lesenswert?

mem = normale Speicheradresse
reg = Bitnummer, 0..2^32/64-1

Was fehlt ist die Möglichkeit, einen variablen Wert zu speichern. Man 
kann nur testen, setzen, löschen, komplementieren. Bei 68020 ging das 
über die Bitfeldbefehle. Das stammt aus einer Zeit, als die Allmacht des 
Microcodes noch nicht durch den RISC Ansatz in Frage gestellt wurde.
Gast #3196923
Lesenswert?

be stucki schrieb:
> Bei den PIC18 gibt es Tabellen, auf die fast wie ein Array zugegriffen
> werden kann (Keine Ahnung wie das genau funktioniert, habs noch nie
> selbst gemacht).

Du meinst nicht die Konstruktion mit Computed-Goto und dem Retlw-Befehl, 
wie sie in der AN556 [1] beschrieben ist? Die bezieht sich auf Bytes.
[1] http://ww1.microchip.com/downloads/en/appnotes/00556e.pdf
Moderator #3196974
Lesenswert?

A. K. schrieb:
> BT/BTC/BTR/BTS mem, reg

Ich dachte bisher immer, diese Instruktionen würden nur mit Bitnummern
bis 31 (bzw. 63) funktionieren. Hab's aber gerade ausprobiert: Man kann
damit tatsächlich auch auf Bit-Seqeuenzen zugreifen, die aus mehreren
Worten zusammengesetzt sind.

A. K. schrieb:
> Was fehlt ist die Möglichkeit, einen variablen Wert zu speichern. Man
> kann nur testen, setzen, löschen, komplementieren.

Ja, das ist allerding ein Wermutstropfen bei der Sache. So etwas wie
1
  bitarray[index] = boolwert; // in C++ mit vector<bool>

ist damit leider nicht direkt in einem Assembler-Befehl umsetzbar.

> Bei 68020 ging das über die Bitfeldbefehle.

Ob der "frickelsprachenhasser" 68020-Assembler programmiert? Dann würde
ich mich von ihm geschlagen geben :)


Edit: Nein, doch nicht, denn es geht hier ja explizit um AVRs:

Dirk F. schrieb:
> Wie sieht es in der AVR Welt aus ?

Auf einem AVR dürfte die Implementierung eine Bit-Arrays in Assembler
noch ein ganzes Stück mehr Schreibarbeit sein als in C.
Gast #3196988
Lesenswert?

flipsi schrieb:

> Bitfields sehen so aus:

So machte ich es bei den ARM7, und teilte einen Long-Wert in 32 bits. 
Man muß sich aber den compilierten Code anschauen, der arbeitet nur in 
ganzen Befehlen für ein Register. Was man da mit der Bitaufteilung zu 
sparen glaubt, erzeugt in Wirklichkeit eine Menge Code.

Bei heutigen µC spielt es oft keine Rolle mehr, wenn man mal ein Byte 
für nur ein bit mißbraucht, und das dann auf Zero oder Not Zero testet. 
Die neueren µC haben reichlich RAM. Dann klappt es auch mit der 
Indizierung.
#3196992
Lesenswert?

Viele Prozessoren kennen keine Bit-Arrays, weil sie den Speicher nicht 
bitweise adressieren können.

Die Sprache C wurde an die Möglichkeiten der damaligen Prozessoren 
angelehnt, deswegen kennt sie nur Bitfelder, aber keine Bit-Arrays.

Viele Mikrocontroller können einen Teil des internen RAM's mit 
speziellen Befehlen bitweise ansprechen. Soweit ich weiß nutzt der C 
Compiler dann auch die bit adressierenden Befehle (z.B. sbi und cbi bei 
8051).

Mit Hilfe von Prozeduren, Funktionen oder Makros kann man sich sowas 
ähnliches wie Bit arrays selbst basteln. Aber der Zugriff auf die 
einzelnen Bits ist in den allermeisten Fällen langsamer, als auf Bytes. 
Man spart nur Speicherplatz.

Deswegen benutze ich in der Regel Bytes, um boolesche Werte zu 
speichern.
#3196998
Lesenswert?

@ Wilhelm Ferkes (ferkes-willem)

>So machte ich es bei den ARM7, und teilte einen Long-Wert in 32 bits.
>Man muß sich aber den compilierten Code anschauen, der arbeitet nur in
>ganzen Befehlen für ein Register. Was man da mit der Bitaufteilung zu
>sparen glaubt, erzeugt in Wirklichkeit eine Menge Code.

Das macht er EINMAL für die Funktion. Die kann man dann beliebig oft 
aufrufen.

>Bei heutigen µC spielt es oft keine Rolle mehr, wenn man mal ein Byte
>für nur ein bit mißbraucht, und das dann auf Zero oder Not Zero testet.

EINS sicher nicht. 70 schon eher, auch wenn heute selbst kleine uCs 
1kB++ RAM haben.
Moderator #3197016
Lesenswert?

A. K. schrieb:
> Yalu X. schrieb:
>> Auf einem AVR dürfte die Implementierung eine Bit-Arrays in Assembler
>> noch ein ganzes Stück mehr Schreibarbeit sein als in C.
>
> Nicht wirklich. Das implementiert man als Makros.

Das meinte ich auch. Das Makro muss ja erst geschrieben werden und
dürfte länger sein als eine entsprechende Funktion in C (s. obiges
Beispiel von Falk). Allein schon deswegen, weil die AVRs keine Shift-
Befehle mit variabler Shift-Weite haben.

> Anders als in C sieht das dann richtig "echt" aus. Als obs Befehle
> wären.

Das stimmt schon, aber nur deswegen, weil es in Assembler im Gegensatz
zu C für solche Operationen keinen syntaktischen Zucker gibt, den es
nachzubilden gälte.

Ein Assembler-Makroaufruf würde etwa so aussehen:
1
  write_bitarray bitarray, r0, r1

Ein C-Funktionsaufruf so:
1
  write_bitarray(bitarray, index, value);

Beides ist gleich (un)übersichtlich. Die C-Version sieht nur deswegen
ungewohnt aus, weil dort die Erwartungshaltung an die Syntax höher ist.
In C++ ist aber auch das kein Problem, weil man dort den []-Operator
überladen kann.
Gast #3197033
Lesenswert?

Stefan Frings schrieb:

> Soweit ich weiß nutzt der C
> Compiler dann auch die bit adressierenden Befehle (z.B. sbi und cbi bei
> 8051).

sbi und cbi gehört sicher eher zum AVR, nicht zum 8051. Dort heißt das 
setb bit oder clr bit oder cpl bit, oder bedingte Sprungbefehle jb, jnb, 
jbc. Den Befehl jbc verwendete ich über die Jahre nur ein einziges mal 
in einem Programm. Aber beim 8051 fand ich in C auch noch keine 
Möglichkeit, die Bitfelder in Einzelbits und Array anzulegen. Er hat 
keinen Pointer auf bits, nur auf Bytes. Die Einzelbits sind da auch für 
Steuerungen als Flaggen (Flags) gedacht, der 8051 war was für kleine und 
mittlere Steuerungsaufgaben. Flag, ich bin da, oder ich bin nicht da.

Und nein, der 8051 war noch nicht speziell auf die Hochsprache C 
optimiert. Als er der Öffentlichkeit vor gestellt wurde, 1980, da kam 
ungefähr auch erst C raus. Im Assembler hatte man aber Bitbefehle, die 
effizienter sind, als Byteverarbeitung.

Aktuell arbeite ich mit dem kleinen PIC12F675, und bin auch über dessen 
Bitverarbeitung erstaunt. In jedem File SFR und RAM läßt sich auch jedes 
bit einzeln verarbeiten. Vor Zeiten machte ich da Byte-Masken, um ein 
bit zu testen, und die warf ich heute mal aus einer alten Software raus.
#3197071
Lesenswert?

Yalu X. schrieb:
> Allein schon deswegen, weil die AVRs keine Shift-
> Befehle mit variabler Shift-Weite haben.

Zumindest für Linksshift kann man die in AVRs meist vorhandene 
Multipliziereinheit verwenden. Nur dass der Arrayzugriff nicht immer 
schneller ist, als die Schleife um das "Schieb um 1"...
1
uint8_t bitnummer;
2
uint8_t meinbit;
3
uint8_t erg1, erg2;
4

5
uint8_t bitnr_to_bit[8] = \
6
{
7
  0x01, 0x02, 0x04, 0x08,
8
  0x10, 0x20, 0x40, 0x80
9
};
10

11
// ...
12
meinbit &= 0x01;
13

14
erg1 &= ~bitnr_to_bit[bitnummer];
15
erg1 |=  bitnr_to_bit[bitnummer] * meinbit;
16
//                              ^^^hier die Multiplikation ;)
17

18
erg2 &= ~(       1 << bitnummer );
19
erg2 |=  ( meinbit << bitnummer );

mfg mf

PS: Dass C eine Fummelsprache ist, kann ich voll bestätigen, solange es 
um Bitgefummel geht.
#3197077
Lesenswert?

frickelsprachenhasser schrieb:
> Warum? Weil C keine ernstzunehmende Programmiersprache ist und auch
> nicht als solche konzipiert wurde. Nichts weiter als ein Treppenwitz der
> EDV-Geschichte. Verwende Assembler, dann musst Du Dich nicht mehr mit
> den Unzulänglichkeiten und Fehlern der sog. "Compiler" herumplagen.

Pah ! Das ganze Halbleitergedöns ist ein Treppenwitz ! Richtige Männer 
verwenden Röhren, Kondensatoren, Spulen und Widerstände für einen 
richtigen Analogrechner, dann musst Du Dich nicht mehr mit den 
Unzulänglichkeiten und Fehlern der sog. Digitalsystem herumplagen.
Gast #3197113
Lesenswert?

Dirk F. schrieb:
> ja ich denke die Frage ist eindeutig ?
> Ich muss in meinem MCU ca. 4x70 Bit abspeichern.

Eindeutig? Nun ja, die Fragestellung als solche zeigt wirklich 
eindeutig, daß du dir einfach zu wenig Gedanken zuvor gemacht hast. Kein 
Mensch MUSS 4x70 Bit abspeichern - sondern er sollte sich vorher 
Gedanken über eine bessere Organisation seiner eigentlichen 
Aufgabenstellung machen.

Aber wenn du partout deinen Algorithmus mit 280 einzelnen Bits machen 
willst, dann hat dir Falk Brunner bereits die fertige Lösung geliefert.

Wozu also jetzt noch die ganze Aufregung? Als selbstzweck, also um sich 
aufzuregen?:
Joachim минифлоть schrieb:
> PS: Dass C eine Fummelsprache ist, kann ich voll bestätigen, solange es
> um Bitgefummel geht.

Nanana. C ist wahrlich keine schöne Sprache, ist auch keine gute 
Sprache, ist auch keine mächtige Sprache und ist auch keine 
unproblematische und leicht verständliche Sprache. Aber C ist schon 
ausreichend benutzbar und bei den allermeisten uC neben Assembler die 
einzige verfügbare Sprache.

Direkte Bitmanipulationen sind gerade bei den jetzt fast 
allgegenwärtigen ARM's ohnehin maschinenmäßig nicht drin, sondern immer 
wieder mit der üblichen "Lade-Verknüpfe-Speichere" Sequenz verbunden - 
eben wegen der grundsätzlichen Struktur dieser CPU's. Da helfen auch die 
neuerdings eingeführten Bit-Adressierungsarten nix. Logische Konsequenz: 
Programme anders strukturieren, dann kann man auch gut damit leben.

Also nicht meckern und C benutzen, solange sich keiner aufrafft und nen 
Compiler für was viel viel viel Besseres schreibt.

W.S.
Persönliche Seite #3197131
Lesenswert?

Dirk F. schrieb:

> Warum gibt es kein Bit-Array in C?

Weid nie ein Bedarf dafür bestand und niemand Bit-Arrays wirklich 
brauchte.

Wenn nämlich ein Bedarf dazu existiert hätte, dann wäre eine 
entsprechende Spracherweiterung längst in ISO-C eingeflössen oder 
zumindest in GNU-C implementiert.

Wenn also in über 20 Jahren C-Geschichte niemand es für nötog hielt, 
BIT-Arrays auch nur zu spezifizieren dann kann es wirklich kein Bedarf 
dafür geben bzw. gegeben haben!
#3197134
Lesenswert?

C ist Maschinen nah und da (fast?) keine CPU indizierte Bitbefehle hat, 
gibt es für nichts auch keine Entsprechung in C.

Man kann sich natürlich leicht eine Bitlib machen und dann aufrufen. Der 
Aufruf zeigt einem dann auch, daß sowas deutlich teurer ist, als 
Bytezugriffe.
Hier mal meine Bitlib aus 8051-Zeiten:
1
/************************************************************************/
2
/*                      Bit Pointer Implementation                      */
3
/*                      SFR bits can not be accessed !                  */
4
/*              Author: Peter Dannegger                                 */
5
/************************************************************************/
6
#define uchar unsigned char
7
#define uint unsigned int
8

9
#define  BIT_START       0x20
10

11
static uint getibit( uchar bitptr )
12
{
13
  uchar code bitmask[] = { 1, 2, 4, 8, 0x10, 0x20, 0x40, 0x80 };
14
  return (uint)bitmask[bitptr & 7] << 8 |       // high byte = bit mask
15
         (uchar) (bitptr / 8 + BIT_START);      // low  byte = byte address
16
}
17

18
void setibit( uchar bitptr )                    // *bitptr = 1;
19
{
20
  uint mask_addr = getibit( bitptr );
21
  *(uchar idata *)mask_addr |= mask_addr >> 8;
22
}
23

24
void clribit( uchar bitptr )                    // *bitptr = 0;
25
{
26
  uint mask_addr = getibit( bitptr );
27
  *(uchar idata *)mask_addr &= ~(mask_addr >> 8);
28
}
29

30
void cplibit( uchar bitptr )                    // *bitptr ^= 1;
31
{
32
  uint mask_addr = getibit( bitptr );
33
  *(uchar idata *)mask_addr ^= mask_addr >> 8;
34
}
35

36
void movibit( uchar bitptr, bit inbit )         // *bitptr = inbit;
37
{
38
  inbit ? setibit( bitptr ) : clribit( bitptr );
39
}
40

41
bit tstibit( uchar bitptr )                     // return *bitptr;
42
{
43
  uint mask_addr = getibit( bitptr );
44
  return *(uchar idata *)mask_addr & mask_addr >> 8;
45
}
Moderator #3197199
Lesenswert?

Johann L. schrieb:
>> Warum gibt es kein Bit-Array in C?
>
> Weid nie ein Bedarf dafür bestand und niemand Bit-Arrays wirklich
> brauchte.

Doch, ich schon. Dirk F. offensichtlich auch. Und sicher noch eine ganze
Reihe mehr.

Der Grund, warum die Bit-Arrays nicht in den Standard einflossen, liegt
vermutlich eher darin, dass sie nur sehr schlecht in das Array-Konzept
von C passen. Eine Umsetzung hätte noch aufgesetzter ausgesehen als die
bereits existierenden Bitfelder, die selbst Dennis Ritchie als "a botch
and a blemish" bezeichnet haben soll.

> Wenn also in über 20 Jahren C-Geschichte niemand es für nötog hielt,
> BIT-Arrays auch nur zu spezifizieren dann kann es wirklich kein Bedarf
> dafür geben bzw. gegeben haben!

Ich hätte sogar einen Ansatz für eine Spezifikation, könnte den aber
nicht mit voller Überzeugung dem C-Konsortium vortragen, weswegen ich
das lieber bleiben lasse. Es würde mir wesentlich leichter fallen,
Gründe für die Abschaffung der Bitfelder zu nennen. Aber auch diese
würden sicher nicht auf fruchtbaren Boden fallen, weil man sie wegen der
Abwärtskompatibilität beibehalten muss.

Es gibt ja immerhin die Möglichkeit, Bit-Arrays mit vorhandenen Sprach-
mitteln zu implementieren. Das sieht zwar im Vergleich zu einer nativen
Implementation syntaktisch nicht so elegant aus, ist aber immer noch
besser, als neue, krüppelige Sprachkonstrukte einzuführen.
Gast #3198655
Lesenswert?

Yalu X. schrieb:
> Ich hätte sogar einen Ansatz für eine Spezifikation,..

Laß es, es wäre sinnlos.

Denk doch mal an die Realisierung auf Maschinenebene bzw. 
Assemblerebene. Bei solchen uC wie den kleinen PIC's haben wir durchaus 
mächtige Bitbefehle, aber das sind ja nun uC, die man wirklich eher in 
Assembler als in C oder Pascal programmieren sollte. Bei allen größeren 
uC werden wir in wenigen Jahren fast nur noch Risc-Architekturen haben, 
die immer nach dem Schema Laden-Ändern-Speichern funktionieren und da 
wird es keine wirklich sinnvollen Bit-Befehle geben.

Das Einzige, was dort Sinn hat, sind Ausdrücke der Art if (A & (1<<nn)), 
aber das sind keine eigentlichen Bitbefehle.

Kurzum, auch jemand, der immer nur in C programmiert, sollte sich 
Gedanken machen um einen geeigneten Entwurf für die Realisierung einer 
Funktionalität und nicht auf sowas wie Bit-Arrays bestehen wollen.

W.S.
Gast #3198755
Lesenswert?

duck&wech schrieb:
> Dirk F. schrieb:
>> C ist für mich die ideale Programmiersprache für MCUs.
>
> Und genau weil genügend Leute aus der Anfangszeit der PC- und µC-Welt
> dies von sich behaupten, ist dieses Gefrickel aus den 80er Jahren des
> vorigen Jahrhunderts immer noch Standard in der µC-Welt.

Und alle Maso- Programmierer finden die hirnverknotende C Freak-Syntax 
nur endgeil, besonders wenn sie Pointer Bugs zwischen dem 
hochoptimierten 
tildeshiftshiftoderundplusgleichdodummyminusminuspointerauf bis zum 
Erbrechen suchen..Lies mal die Scheisse ein Jahr später und verstehe 
was. Da lob ich mir einen Compiler, der mir nicht sooooo viele 
Freiheiten läßt, wenns auch vielleicht einen Zyklus mehr braucht. Na und 
- bei den Prozessorleistungen heut ?
#3198765
Lesenswert?

grrrrrr schrieb:

> Und alle Maso- Programmierer finden die hirnverknotende C Freak-Syntax
> nur endgeil, besonders wenn sie Pointer Bugs zwischen dem
> hochoptimierten
> tildeshiftshiftoderundplusgleichdodummyminusminuspointerauf bis zum
> Erbrechen suchen.

Hmm. Dann muss ich was falsch machen.
Pointer Bugs kommen bei mir selten vor und wenn, dann such ich die nicht 
bis zum Erbrechen, sondern hab die eigentlich ziemlich schnell dingfest 
gemacht.

> Lies mal die Scheisse ein Jahr später und verstehe
> was.

Kein Problem damit. Ist dir schon mal in den Sinn gekommen, dass hier 
genug Leute rumhängen, die Code, den sie noch nie zuvor gesehen haben in 
10 Minuten oder weniger analysieren können?
Probier das mal mit einem vollständigen Assembler Programm und frag 
dich, wo der Stack aus dem Tritt gekommen ist bzw. wo welcher 
Funktionsaufruf welches SREG-Flag verstellt hat.

> Da lob ich mir einen Compiler, der mir nicht sooooo viele
> Freiheiten läßt, wenns auch vielleicht einen Zyklus mehr braucht. Na und
> - bei den Prozessorleistungen heut ?

"Man kann in jeder Sprache Fortran Programme schreiben."


Ja - kann man. Man muss aber nicht.


Edit: Nicht, das wir uns falsch verstehen. Ich halte C keineswegs für 
das Beste seit geschnittenem Brot. Es ist nur ein Werkzeug. Und wie mit 
allen Werkzeugen muss man eben lernen, damit umzugehen.
Persönliche Seite #3198771
Lesenswert?

Schön, das die BASCOM-Fraktion auch hier vertreten ist :-)
Ja, C ist schon schlimm für Leute die es nicht verstehen.


Einzel-Bit-Zugriffe sind ineffizient, deshalb braucht man auch kein 
Bit-Array. Brauchen tut man das wirklich nur bei Bitstreams oder 1-Bit 
LCDs.

Ich finde wie Flipsi oder Michael S1 es gezeigt haben (Bit-Field oder 
Array mit Makro) ist es gut nachvollziehbar.

Man kann die Bit-Field Version ja noch mit Michaels Indizierung 
erweitern:
1
#define BIT(x) bytes[x>>3].bit##(x&0x7)

Geht natürlich nicht für Schleifen, aber wenn man schon eine Schleife 
über einzelne Bits machen muss, gibt es bestimmt auch eine effizientere 
Verarbeitung (auf Byte-Basis). Dafür müsste man die Schleife halt 
"entrollen".
OP #3199136
Lesenswert?

Hallo,
also mit so einer Resonanz hätte ich nicht gerechnet.
Danke für die Hinweise und Code Beispiele.

Als Zusatzinformation folgende Schaltungebeschreibung:
AUf dem Main board sitzt der PIC18, der über SPI maximal 5 Steckkarten 
mit Relais ansteuert.
Jede Steckkarte hat 74 Relays.
Jetzt muss sich die MCU merken, welche Relais angesteuert wurden, um 
weitere Verknüpfungen zu machen.
Da wäre hat ein 2-dimensionales Bit Array genial gewesen, eine Dimension 
für die Relay Nummer 1-74, die andere für die Kartennummer 1-5.

Jetzt werde ich wohl ein 1 dimensionales char Array mit 74 Stellen 
erstellen, in jedem Byte 5 Bit nutzen.

Gruß Dirk
#3199167
Lesenswert?

Dirk F. schrieb:

> Jetzt werde ich wohl ein 1 dimensionales char Array mit 74 Stellen
> erstellen, in jedem Byte 5 Bit nutzen.

Ist zwar möglich, aber eigentlich extrem kompliziert.

Wenn du für jede Karte  74/8 gleich 10 Bytes benutzt um darin in jedem 
Bit ein Relais abzulegen, dann rechnet sich das ganze für den µC auch 
gleich viel einfacher. Und du verschwendest weniger Bits.

Mann! Das ist doch einfach nur Division durch 8 mit Restbildung! Das 
hast du in der Grundschule gelernt! 8-jährige können das.
Wir leben schon in einer seltsamen Zeit, in der die Menschen Angst davor 
haben einfachste Rechnungen durchzuführen. Und dann wundern wir uns, 
wenn immer mehr Jugendliche in die Handyfalle tappen einfach weil sie 
die realen Kosten ihres Handys in einem Jahr nicht ausrechnen können.
#3199248
Lesenswert?

A. K. schrieb:
> Gibts Geld zurück, wenn man RAM nicht verwendet? Der Unterschied wird
> erst relevant, wenn das RAM knapp wird.

Nun.
So gesehen könnte er dann ja auch einfach ein uint8_t[5][74] benutzen?

Aber ok. Das mit dem kompliziert nehm ich zurück. Da hast du schon recht 
- das ist kein wirkliches Argument, selbst dann wenn das Übertragen der 
Relaisstände auf die einzelnen Karten dann zu einer Array-Zugriffsorgie 
ausartet.
Mich haben eigentlich die verschenkten Bits geärgert und das weiter oben 
ja schon Code gepostet wurde, der genau dieses Problem nicht hat.

Und bei Relais Bearbeitung spielt dann auch das Fehlen eines 
Barrel-Shifters nicht wirklich eine Rolle.
#3199289
Lesenswert?

@ A. K. (prx)

>Gibts Geld zurück, wenn man RAM nicht verwendet? Der Unterschied wird
>erst relevant, wenn das RAM knapp wird.

Jain. Aber mal 5 Minuten vorausschauend zu denken ist wohl selten 
verkehrt. Zumal wir es hier nicht mit einem komplexen Problem zutun 
haben, es ist, wie so oft, ein Luxusproblem.
(Firma: DC3AX) #3199636
Lesenswert?

Nochmal ganz zurück zum eigentlichen Bit Problem...

Ich denke das Problem wird einfach auf der falschen CPU gelöst. 
Schließlich kann ein SMT32F oder STM32M auch im RAM auch bitbanding 
access.
Ein Bit aus dem RAM wird durch ein word in einem anderen Adressbereich 
repräsentiert. Schreibt man in der bitbanding area eine 0 in ein word, 
wird das correspondierende Bit auf 0 gesetzt, sonst auf 1.

Vorteile:
Zugriff per uint32_t array[] möglich ohne eine neue Type einzuführen.
Zugriff ist atomic für setzen und löschen eines Bits.
Zugriff erfordert keine bitshift Operationen, obwohl ein Cortex diese 
als load and shift in einem Schritt machen könnte.
Zugriffe werden an einigen Stellen sehr viel schneller und Code wird 
kleiner:

Statt
if (a > 0) then bla[n] |= (1<<x); else bla[n] &= ~(1<<x);
schreibt man einfach
bla[n] = a;

Gruß
Ulrich
Persönliche Seite #3199714
Lesenswert?

Yalu X. schrieb:
> Johann L. schrieb:
>>> Warum gibt es kein Bit-Array in C?
>>
>> Weil nie ein Bedarf dafür bestand und niemand Bit-Arrays wirklich
>> brauchte.
>
> Doch, ich schon. Dirk F. offensichtlich auch. Und sicher noch eine ganze
> Reihe mehr.
>
> Der Grund, warum die Bit-Arrays nicht in den Standard einflossen, liegt
> vermutlich eher darin, dass sie nur sehr schlecht in das Array-Konzept
> von C passen. Eine Umsetzung hätte noch aufgesetzter ausgesehen als die
> bereits existierenden Bitfelder, die selbst Dennis Ritchie als "a botch
> and a blemish" bezeichnet haben soll.
>
>> Wenn also in über 20 Jahren C-Geschichte niemand es für nötig hielt,
>> BIT-Arrays auch nur zu spezifizieren, dann kann es wirklich kein
>> Bedarf dafür geben bzw. gegeben haben!
>
> Ich hätte sogar einen Ansatz für eine Spezifikation, könnte den aber
> nicht mit voller Überzeugung dem C-Konsortium vortragen, ...

Falls du deinen Spieltrieb nicht bremsen kannst: Wie wär's mit einem 
Proof-of-Concept?

1) Nimm dir die GCC-Quellen
2) Definiere einen neuen Address Space __bitmem. Der neue AS ist
   disjunkt zu allen anderen AS (Hook: TARGET_ADDR_SPACE_SUBSET_P).
   Es ist also nicht möglich, bei Zeigern den AS-Qualifier "hinzu"
   oder "weg" zu casten.

3) Beim Lesen wird 1 Bit gelesen und zum Zieltyp expandiert:
1
long get_bit (__bitmem long *p)
2
{
3
    return *p;
4
}

4) Beim Schreiben wird nut Bit 0 geschrieben oder (wahlweise,
   etwa über einen neuen Schalter) wird eine 0 genau dann
   geschrieben, wenn die zu schreibende Variable == 0 ist.

5) "Abgeholt" werden die neuen Lade- und Speicher-Insns für
   den neuen AS in den mov<mode> insns, also movqi, movhi, etc.
   Hier wied auch die Adressberechnung ausgegeben und es werden
   Spezialfälle behandelt, etwa bei direkter Adressierung.

6) GCC neu compilieren und Testprogramm damit übersetzen.

7) Fertig :-)
Gast #3199751
Lesenswert?

Indizierte bits gibts also nicht. Beim 8051 kann man sagen, setb 125, 
das spricht dann Byte 0x2F und das bit 5 dort an, oder jb 125, 
Sprungadresse, bedingte Sprungbefehle nach Bitzustand, sonst geht da 
nichts. Es war aber damals ganz was modernes, Einzelbits als Flaggen 
Merker für Steuerungen. Man kann die 125 nie als Indiz gebrauchen. Alles 
andere macht Bytebefehle im Code.

Bei heute gigantischem RAM würde ich auch ein Byte nur für eine Null 
oder Eins verbrauchen. Wayne interessierts?

1976, als RAM und ROM wirklich sehr knapp war, und man froh war, nur 256 
Bytes für einen Speicher her zu stellen, da machte man sich noch einen 
Kopf um effiziente Befehlssätze, wie beim 8048, die nur ein Byte haben.

Sowas Bitbefehle in einen C-Sprachschatz zu übernehmen, halte ich für 
etwas schräg. Viele Prozessoren außer den PIC und 8051 kennen keine 
Einzelbitbefehle, und haben keinen Einzelbitprozessor, wie es der 8051 
hat. Es wäre schön gewesen, wenn ein 8051 einen Pointer auf Bits gehabt 
hätte, aber der Befehlssatz ist mit 256 Befehlen in 8 bit auch schon 
vollständig auscodiert, da gibt es keinen Platz mehr.
#3199777
Lesenswert?

Wilhelm Ferkes schrieb:
> Sowas Bitbefehle in einen C-Sprachschatz zu übernehmen, halte ich für
> etwas schräg.

Es passt nicht wirklich gut in eine Sprache, die sich relativ dicht an 
den Fähigkeiten üblicher Maschinen orientiert. Anders bei 
Programmiersprachen mit wesentlich höherem Abstraktionsgrad. Wie oben 
schon erwähnt wurde kann man auch schon die Bitfelder eher als Irrtum 
denn als Errungenschaft sehen.

Gäbe es nur C, wäre die Diskussion um die Entwicklung der Sprache offen. 
Aber dank u.A. C++ erscheint mir das sinnarm.

Viele lehnen C++ bei µCs ob eines angeblich exzessiven 
Ressourcenverbrauchs ab. Was Unfug ist, wenn man weiss was man tut. 
Exakt solche Sachen lassen sich da aber sehr gut und durchaus effizient 
abbilden.
Gast #3204649
Lesenswert?

>Aber der Zugriff auf die
>einzelnen Bits ist in den allermeisten Fällen langsamer, als auf Bytes.
Die CPU liesst (auch wenn sie explizite Bitbefehle hat) zumindest immer 
1 Byte ein, schreibt ggfs zurück (RMW), also ist es von daher egal.
Evtl zus Operationen (ob OPCode-intern oder mit sep ASM.-Befehl 
umgesetzt) brauchen nat. nochmal Zeit, ggfs weiteren Platz im ROM.


>Und nein, der 8051 war noch nicht speziell auf die Hochsprache C
>optimiert. Als er der Öffentlichkeit vor gestellt wurde, 1980, da kam
>ungefähr auch erst C raus.
1. gibt es  bei keiner CPU wirkliche Features speziell für C (ausser nen
   Stack, aber das hat wohl jeder (ausser die kleinsten PICs und die
   ältesten Intels)
2. hat man das "für Hochsprachen optimiert" bereits 1979 bei der
   Vorstellung des 68k behauptet.
3. ist reiner Marketing-Quatsch.
   Denn sinnvoll in ASM prgorammiert geht automatisch auch sinnvoll
   in ner Hochsprache.


Befehle um mit zusammenhängeden Bits umzugehen (bsp mit 1..2 
Index-Regs), sollten (neuere) CPUs schon haben.
Gast #3204665
Lesenswert?

>werden wir in wenigen Jahren fast nur noch Risc-Architekturen haben,
>die immer nach dem Schema Laden-Ändern-Speichern funktionieren und da
>wird es keine wirklich sinnvollen Bit-Befehle geben.
Vonwegen. Selbst bei "Schema Laden-Ändern-Speichern" CPUs macht das 
Sinn, weil 1. atomar möglich und 2. nur 1 statt 3 ASM-Befehlen.
Persönliche Seite #3204675
Lesenswert?

MCUA schrieb:
>>werden wir in wenigen Jahren fast nur noch Risc-Architekturen haben,
>>die immer nach dem Schema Laden-Ändern-Speichern funktionieren und da
>>wird es keine wirklich sinnvollen Bit-Befehle geben.
> Vonwegen. Selbst bei "Schema Laden-Ändern-Speichern" CPUs macht das
> Sinn, weil 1. atomar möglich und 2. nur 1 statt 3 ASM-Befehlen.

Daß die Operation atomar durchgeführt werden kann ist auf Mulicore-MCUs 
sogar unabdingbar, denn ein globales IRQ-Disable wirkt nicht auf die 
anderen Cores.

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren