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
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.
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];
@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.
> 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.
Hallo, also das sehe ich ja ganz anders.
Ich komme aus der Assembler Welt.
Wer den PIC kennt, der weiß was ich meine.
C ist für mich die ideale Programmiersprache für MCUs.
Dirk
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.
>>>K&R, The C Programming Language, 1978, Seite 136, Bit Fields.
Kenne das Buch leider nicht .
Das heißt, laut C Definition geht es, nur es wird in den Compilern nicht
verwendet ?
LG Dirk
Ich kenne keinen Compiler, der es nicht kann.
Das zitierte Buch ist die "Bibel" vom Erfinder der Sprache C.
Such mal nach "bit field" und nicht nach "bit array".
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.
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.
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.
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.
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]].
Yalu X. schrieb:> Und welcher Assemblersprache unterstützt Bit-Arrays, wenn ich fragen> darf?
Alle x86 beispielsweise. Ein paar Controller sind aber wohl auch mit von
der Partie.
Hallo,
tja, die Schaltung ist ja schon fertig mit dem PIC18.
Da kann ich jetzt nicht kurzfristig auf eine neu CPU Typ umsteigen.
Trotzdem Danke für den Hinweis.
LG Dirk
Bitarrays kann man in Embedded C durch einen Named Address Space
darstellen. Wer Lust hat, kann eine entsprechende Unterstützung zB in
GCC reinklöppeln. :-)
Damit kann man dann auch die Adresse eines Bits nehmen und hat
"richtige" Arrays, mit denen auch memcpy etc. funktioniert.
__attribute__((packed))// oder was Dein Compiler hier möchte
5
{
6
uint8_tbit0:1;
7
uint8_tbit1:1;
8
uint8_tbit2:1;
9
uint8_tbit3:1;
10
uint8_tbit4:1;
11
uint8_tbit5:1;
12
uint8_tbit6:1;
13
uint8_tbit7:1;
14
}bytes[10];
15
16
intmain(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
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
intmain(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
A. K. schrieb:>> Und welcher Assemblersprache unterstützt Bit-Arrays, wenn ich fragen>> darf?>> Alle x86 beispielsweise.
Sicher? Mit welchen Befehlen bzw. Adressierungsarten geht das?
Yalu X. schrieb:> Sicher? Mit welchen Befehlen bzw. Adressierungsarten geht das?
BT/BTC/BTR/BTS mem, reg
Die Mikrocode-Rechnerei ist aber nicht gratis, diese Befehle sind bei
feststehendem Wort, also Bits 0..31/63, möglicherweise langsamer als die
Ersatzsequenz.
Korrektur: Gibts erst ab 386.
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.
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
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.
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. Anders als in C sieht
das dann richtig "echt" aus. Als obs Befehle wären.
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.
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.
@ 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.
Ein Kompromiss wäre, wenn sich das programmtechnisch von 4 Arrays à 70
Bits auf ein 70 Byte langes Array à 4 Bits umbauen liesse. Wenn man die
4er Komponente primär als Maske statt Nummer rumschleppt ist das recht
effizient.
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.
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.
Wilhelm Ferkes schrieb:> Und nein, der 8051 war noch nicht speziell auf die Hochsprache C> optimiert. [...] Aktuell arbeite ich mit dem kleinen PIC12F675,
Die PICs mit 12/14-Bit Befehlen sind für eine C Implementierung freilich
noch ärger als 8051. Allerdings ist die 12er Architektur in ihrem
Ursprung noch einige Jahre älter als 8051.
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_tbitnummer;
2
uint8_tmeinbit;
3
uint8_terg1,erg2;
4
5
uint8_tbitnr_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.
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.
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.
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!
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:
#define TestBit(ByteArray, BitIdx) (ByteArray[BitIdx>>3] &
(1<<(BitIdx & 7)))
SetBit und ClrBit nach gleichem Schema
Das kann man natürlich auch als Funktionen (ggf. mit inline)
implementieren.
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.
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.
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 ?
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.
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".
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
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.
Karl Heinz Buchegger 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.
Ich finde es einfacher als deinen Vorschlag. ;-)
A. K. schrieb:> Karl Heinz Buchegger 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.>> Ich finde es einfacher als deinen Vorschlag. ;-)
Bei 3 verschenkten Bits pro Byte?
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.
Dirk F. schrieb:> Jetzt werde ich wohl ein 1 dimensionales char Array mit 74 Stellen> erstellen, in jedem Byte 5 Bit nutzen.
Warum willst Du unnötig Hardware verschwenden?
Das SPI gibt immer ganze Bytes aus und die SRG (74HC595) sind auch 8 Bit
breit.
74 / 8 sind 10 SRG.
74 / 5 sind aber schon 15 SRG.
Ich würde an dieser Stelle ohnehin überlegen, ob an Stelle von
Schieberegistern vielleicht 74HC259 einfacher zu verwenden sind. Da
lassen sich die Relais einzeln ansteuern.
Peter Dannegger schrieb:> 74 / 8 sind 10 SRG.> 74 / 5 sind aber schon 15 SRG.
Er hat 5 Karten mit je 74 Relais. Ich nehme doch stark an, dass die
Shifter auf der jeweiligen Karte sind, um nicht so viele Verbindungen zu
benötigen. Die SPI-Bytes aus 8 aufeinanderfolgenden Array-Bytes
einzusammeln ist wahrlich kein Hexenwerk. Und Relais sind auch keine
Rennpferde.
@ 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.
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
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
longget_bit(__bitmemlong*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 :-)
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.
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.
A. K. schrieb:> Johann L. schrieb:>> Doch, wieso denn nicht?>> Im 8051 Befehlssatz gibt es sie nicht. Nur direkt adressierte Bits.
Ja, und? Gibt man eben eine Befehlsfolge aus, das wied das Ding wohl
können. Schieben, Maskieren, ...
>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.
>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.
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.
MCUA schrieb:> 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.Fast immer. Die CPUs der TI9900 Familie hatten zusätzlich zum
Speicherbus noch einen weiteren Adressraum mit 1 Bit Datenbreite. Darin
war das naturgemäss nicht nötig.