Ich habe in C/C++ (ATmega328) zum Speichern der Ausgangszustände ein Bitfeld definiert:
1
structAusgaenge// jeweils 1 Bit fuer Speicherung der Zustaende der Ausgänge
2
{
3
uint16_tA1:1;
4
uint16_tA2:1;
5
uint16_tA3:1;
6
uint16_tA4:1;
7
uint16_tA5:1;
8
uint16_tA6:1;
9
uint16_tA7:1;
10
uint16_tA8:1;
11
uint16_tA9:1;
12
uint16_tA10:1;
13
uint16_tA11:1;
14
uint16_tA12:1;
15
uint16_tA13:1;
16
}
17
Ausgang;
Nun wollte ich folgendes machen:
1
for(uint8_ti=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?
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.
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.
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) {
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.
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.
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:
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_tGetAusgang(inti)
2
{
3
switch(i)
4
{
5
case1:returnAusgang.A1;
6
case2:returnAusgang.A2;
7
case3:returnAusgang.A3;
8
...
9
case13:returnAusgang.A13;
10
}
11
return0;/* wasimmer der Default sein soll im Fehlerfall */
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.
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.
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.
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.
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...
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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!
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.
Ich denke, es ist schon ein Unterschied, ob man einen kleinen Mikrocontroller programmiert (größtenteils Hardware Programmierung) oder ein Office-Paket.
Ich denke, es ist schon ein Unterschied, ob man einen kleinen
Mikrocontroller programmiert (größtenteils Hardware Programmierung) oder
ein Office-Paket.
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.
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 ;-).
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?
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.
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.
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.
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.
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.
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.
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.
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.?
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...
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.
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?
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.
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.
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.
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).
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.
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?
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.
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.
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...
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.
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).
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).
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.