Hallo,
ich lese gerade ein C-Buch und dort steht, dass manche Compiler keinen
Pfeil-Operator bei Bitfeldern erlauben. Ist das wirklich so?
Ich weiß, dass man nicht auf die Adressen der einzelnen Membervariablen
zugreifen darf. Aber ein Zeiger auf die gesamte Struktur (bit field)
soll tabu sein? D.h. bei Argumenten von Funktionen solche Objekte immer
kopieren und nicht per Zeiger übergeben?
Sowas soll wohl manchmal in die Hose gehen:
zitter_ned_aso schrieb:> Hallo,>> ich lese gerade ein C-Buch und dort steht, dass manche Compiler keinen> Pfeil-Operator bei Bitfeldern erlauben. Ist das wirklich so?
Mag sein, dass es die gibt. Ich habe noch keinen gesehen, aber ich
benutze auch nicht so viele Compiler, und Bitfelder verwende ich auch
nur selten.
Compiler, die das nicht können, sind allerdings nicht konform. Ich sehe
eigentlich auch keinen vernünftigen Grund, das nicht zu unterstützen.
zitter_ned_aso schrieb:> ich lese gerade ein C-Buch und dort steht, dass manche Compiler keinen> Pfeil-Operator bei Bitfeldern erlauben.
Lässt sich in dieser Form kaum widerlegen, denn wer kennt schon alle
Compiler.
> Ist das wirklich so?
IMHO nicht, was den C Standard angeht.
Yalu X. schrieb:> In deinem Beispiel ist> test eine Struktur und i, j, k sind Bitfelder.
Und auf sie kann man mit dem "->"-Operator zugreifen?
Darum geht es ja.
zitter_ned_aso schrieb:> Yalu X. schrieb:>> In deinem Beispiel ist test eine Struktur und i, j, k sind Bitfelder.>> Und auf sie kann man mit dem "->"-Operator zugreifen?
Ja. Yalu hat recht: Das, was du hier als "Membervariablen" bezeichnet
hast, sind eigentlich Bifelder, wogegen das, was du als "Bitfeld"
bezeichnest, eine Struktur ist. Auf Struktur-Elemente darf man per ->
zugreifen, auch wenn es sich bei diesen Elementen um Bitfelder handelt.
Es wird ja kein Zeiger auf das Bitfeld dereferenziert, sondern nur einer
auf die Struktur. Zeiger auf Bitfelder sind nicht möglich.
So, hier ist der Text.
Ja, das was ich als Membervariable bezeichnet habe ist ein Bitfeld. Aber
das sind nur Begriffe. Es geht um den Zugriff auf diese Variablen.
Das Buch (C als erste Programmiersprache) ist in der x-ten Auflage und
die Autoren kommen nicht aus Indien, sondern aus Deutschland.
Darum frage ich ja, ob man da aufpassen muss. Ich habe das nämlich bis
jetzt nie gehört.
Es würde ja dazu führen
zitter_ned_aso schrieb:> D.h. bei Argumenten von Funktionen solche Objekte immer> kopieren und nicht per Zeiger übergeben
Und das ist doch Quatsch.
zitter_ned_aso schrieb:> Das Buch (C als erste Programmiersprache) ist in der x-ten Auflage und> die Autoren kommen nicht aus Indien, sondern aus Deutschland.
Das allein hat halt nichts zu sagen.
Selbst, falls es wirklich mal solch einen Compiler gegeben hätte,
zumindest die Begründung ist völliger Humbug. Natürlich kann man keine
Adresse eines Bitfeldes nehmen, aber um eine solche geht es beim
Operator -> ja ohnehin nicht: dort wird mit der Adresse der kompletten
Struktur operiert.
Ich bezweifle aber, dass es jemals einen derartigen Compiler gegeben
hat, denn der Operator -> ist ja weiter nichts als ein * gefolgt von
einem Punkt, nur dass man bei Anwendung dieser beiden Operatoren halt
noch ein Klammerpaar setzen müsste. Das erschien wohl den Herren
Kernighan und Ritchie zu umständlich, weshalb sie dafür einen
„Kurzschluss“ erfunden haben.
zitter_ned_aso schrieb:> Ja, das was ich als Membervariable bezeichnet habe ist ein Bitfeld. Aber> das sind nur Begriffe. Es geht um den Zugriff auf diese Variablen.
Nun, es hatte erst den Anschein, dass die Verwirrung möglichweise aus
einer falschen Interpretation der Begriffe kommt.
> Das Buch (C als erste Programmiersprache) ist in der x-ten Auflage und> die Autoren kommen nicht aus Indien, sondern aus Deutschland.
Die angehängte Textpassage halte ich für Blödsinn. Wie schon
geschrieben, wird hier mit dem -> gar nicht die Adresse des Bitfeldes,
sondern die der Struktur genutzt, somit ergibt die dort angegebene
Begründung schlicht keinen Sinn.
zitter_ned_aso schrieb:> So, hier ist der Text.
Ok, das ist natürlich ein Fehler.
Wenn "Pfeil-Operator ->" durch "Adressoperator &" ersetzt würde, ergäbe
das zumindest ein wenig Sinn. Eigentlich verbietet der C-Standard die
Anwendung des Adressoperators auf Bildfelder. Wenn ein Bitfeld aber die
Größe und das Alignment eines Integertyps (char, short, int oder long)
hat, könnte ein Compilerbauer auf die Idee kommen, den Adressoperator in
diesem Fall einen Zeiger auf den entsprechenden Integertyp liefern zu
lassen. Das wäre aber sehr architektur- und compilerspezifisch, da das
Speicherabbild von Bitfeldern im Standard nicht spezifiziert ist. Zudem
wird kaum ein Programmierer ein Bitfeld verwenden, das exakt einem
normalen Integertyp entspricht.
Jörg W. schrieb:> Das erschien wohl den Herren> Kernighan und Ritchie zu umständlich, weshalb sie dafür einen> „Kurzschluss“ erfunden haben.
Für mich war der Pfeil immer "syntactic sugar".
MfG Klaus
Klaus schrieb:> Für mich war der Pfeil immer "syntactic sugar".
Viel mehr ist es auch nicht.
Meine Vermutung: die PDP-11 hatte ja MMIO devices, die dürften sehr
ähnlich aufgebaut gewesen sein wie das, was wir jetzt bei vielen ARMs
haben. Damit bietet es sich dann an, einen Zeiger auf die Geräteadresse
zu haben und die Geräteregister als struct zu definieren. C ist ja vor
allem erschaffen worden, um damit das Betriebssystem UNIX selbst
programmieren zu können, und wenn man nun die ganze Zeit auf
irgendwelchen Geräteregistern herumhampelt, schreibt es sich eben (erst
recht auf einem alten Fernschreiber) sehr blöd, wenn man die ganze Zeit
sowas schreiben muss:
Jörg W. schrieb:> sehr blöd, wenn man die ganze Zeit> sowas schreiben muss:>> *(deviceinstance).DATA = mydata;> *(deviceinstance).CNTRL |= 1; /* start transaction */> while ((*(deviceinstance).STATUS & 1) != 0)> /* wait until completed */ ;
Zudem birgt die zuckerfreie Variante die Gefahr falsch gesetzter
Klammern. Mit -> passiert das nicht ;-)
SCNR
Jörg W. schrieb:> Klaus schrieb:>> Für mich war der Pfeil immer "syntactic sugar".>> Viel mehr ist es auch nicht.
Das ist eine direkte Folge der nicht sonderlich guten Idee, die
Dereferenzierung als Präfix-Operator zu implementieren. Als
Postfix-Operator wäre die Sprache deutlich eleganter geraten und der
Pfeil-Operator wäre überflüssig.
So wäre die Anfängern nicht immer leicht zugängliche Entschlüsselung von
*x[] und (*x)[] in Postfix-Notation deutlich leichter gefallen.
A. K. schrieb:> Das ist eine direkte Folge der nicht sonderlich guten Idee, die> Dereferenzierung als Präfix-Operator zu implementieren.
Ja, kann man so sehen.
Andererseits dürfte es damals keine großen Vergleichsmöglichkeiten
gegeben haben für Zeigeroperationen in Hochsprachen (Pascal hat sowas
auch, ist aber mehr oder weniger parallel entstanden), und naja,
sonderlich viel Wissenschaft haben die Herren um UNIX sicher auch nicht
gerade darum betrieben. Sonst hätten sie ja gleich bei Multics mitmachen
können. :-)
Manchmal macht man halt auch Designfehler. Oder, um Ken Thompson mal zu
zitieren auf die Frage, was er denn anders machen würde: "I'd spell
creat with an e." ;-)
Möglicherweise wollte der Autor eigentlich davor warnen, dass die Frage
nach Big und Little Endian Systemen einem hier ordentlich den Spaß
verderben können.
Bei Bitfeldern plötzlich auf das Thema "." und "->" Operator zu
schwenken, bedeutet entweder, dass hier Kontext fehlt oder sich der
Autor gerade etwas verrannt hat...
Jörg W. schrieb:> Andererseits dürfte es damals keine großen Vergleichsmöglichkeiten> gegeben haben für Zeigeroperationen in Hochsprachen
In der Entwicklungsgeschichte von C war es anfangs ein Postfix-Operator!
C geht auf B zurück, und das war von BCPL inspiriert. In BCPL schreibt
sich die Dereferenzierung je nach Version als V*[I] oder V!I bei Arrays
und V*() oder V!() bei Funktionen.
Dieses ursprüngliche * in BCPL war freilich keine gute Idee, weil V*(E)
gleichermassen als indirekter Funktionsaufruf und Multiplikation
verstanden werden kann. Das führte in BCPL später zu ! statt *, also zu
V!(E). Die Sprache B bog vielleicht vor dieser Änderung ab und löste das
Problem mit Präfix-*. Die zweite BCPL-Version wäre m.E. der bessere Weg
zu B und C gewesen, mit p!.x statt (*p).x / p->x in C.
Mikroskop schrieb:> dass die Frage nach Big und Little Endian Systemen einem hier ordentlich> den Spaß verderben können
Byte order ist allerdings noch was anderes als Bit order.
Letztlich ist bei Bitfields praktisch alles "implementation-defined",
damit muss man leben. Portabler Code popelt sich daher mühselig die Bits
mit den normalen Bit-Operationen (& / |) zusammen und auch die Bytes
werden hin und her geschoben in der Hoffnung, dass der Compiler das
schon richten wird.
Jörg W. schrieb:> Mikroskop schrieb:>> dass die Frage nach Big und Little Endian Systemen einem hier ordentlich>> den Spaß verderben können>> Byte order ist allerdings noch was anderes als Bit order.>> Letztlich ist bei Bitfields praktisch alles "implementation-defined",> damit muss man leben. Portabler Code popelt sich daher mühselig die Bits> mit den normalen Bit-Operationen (& / |) zusammen und auch die Bytes> werden hin und her geschoben in der Hoffnung, dass der Compiler das> schon richten wird.
Das kommt auf den Anwendungsfall an. Bitfelder sind halt nicht für die
Umsetzung von binären Schnittstellen zu anderen Systemen gedacht,
sondern um beim Speichern von Daten im RAM Platz zu sparen. Wenn man sie
auch nur so einsetzt, interessiert einen die implementationsspezifische
Anordnung der Bitfelder gar nicht.
Rolf M. schrieb:> Das kommt auf den Anwendungsfall an. Bitfelder sind halt nicht für die> Umsetzung von binären Schnittstellen zu anderen Systemen gedacht,> sondern um beim Speichern von Daten im RAM Platz zu sparen.
Möglicherweise haben K&R sie auch schon für sowas wie Hardwarezugriffe
benutzt, weiß nicht, müsste man sich den alten PDP-11-Code von UNIX mal
ansehen. Dafür taugen sie natürlich auch, da der sowieso immanent
systemabhängig ist.
Binäre Schnittstellen mit anderen Systemen wären natürlich der
Anwendungsfall, wo man sie wohl ansonsten am ehesten gebrauchen könnte.
Das letzte Bit aus dem Speicher rauszuquetschen, lohnt in aller Regel
die Performanceeinbuße gar nicht, die damit einher geht.
Jörg W. schrieb:> Binäre Schnittstellen mit anderen Systemen wären natürlich der> Anwendungsfall, wo man sie wohl ansonsten am ehesten gebrauchen könnte.> Das letzte Bit aus dem Speicher rauszuquetschen, lohnt in aller Regel> die Performanceeinbuße gar nicht, die damit einher geht.
Klar, wenn man nur eine einzelne Instanz hat, lohnt das in der Regel
nicht. Ich sehe den Vorteil z.B. dann, wenn man eine größere Anzahl der
gleichen Datenstruktur hat und dort nicht für jedes Element von zwei Bit
Größe gleich ein ganzes Byte verbrauchen will. Und das natürlich nicht
auf dem PC, sondern z.B. auf einem AVR mit nur ein paar Hundert Bytes
RAM. Aber ja, die Anwendungsfälle sind begrenzt.