Forum: PC-Programmierung C: Bitfiled und arrow-Operator


von zitter_ned_aso (Gast)


Lesenswert?

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:
1
  struct test{                                                         
2
      unsigned int i:2;                                                 
3
      unsigned int j:2;                                                 
4
      unsigned int k:2;                                                 
5
   };                                                                   
6
                                                                        
7
   struct test t;                                                       
8
   struct test *p_t = &t;                                               
9
                                                                        
10
   p_t->i = 1;                                                          
11
   printf("val: %u\n", p_t->i);

Ist das echt so?

von Rolf M. (rmagnus)


Lesenswert?

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.

von Yalu X. (yalu) (Moderator)


Lesenswert?

Du hast nicht verstanden, was ein Bitfeld ist. In deinem Beispiel ist
test eine Struktur und i, j, k sind Bitfelder.

von (prx) A. K. (prx)


Lesenswert?

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.

von zitter_ned_aso (Gast)


Lesenswert?

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.

von Rolf M. (rmagnus)


Lesenswert?

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.

: Bearbeitet durch User
von Yalu X. (yalu) (Moderator)


Lesenswert?

Wie lautet denn die fragliche Passage in dem C-Buch genau?

von zitter_ned_aso (Gast)


Angehängte Dateien:

Lesenswert?

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.

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

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.
1
  a->b; // ist dasselbe wie
2
  (*a).b;

von Rolf M. (rmagnus)


Lesenswert?

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.

von Yalu X. (yalu) (Moderator)


Lesenswert?

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.

von Wie (Gast)


Lesenswert?

zitter_ned_aso schrieb:
> C als erste Programmiersprache

wie bist du auf das Buch gekommen?

von Klaus (Gast)


Lesenswert?

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

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

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:
1
  *(deviceinstance).DATA = mydata;
2
  *(deviceinstance).CNTRL |= 1; /* start transaction */
3
  while ((*(deviceinstance).STATUS & 1) != 0)
4
    /* wait until completed */ ;

von Yalu X. (yalu) (Moderator)


Lesenswert?

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

von (prx) A. K. (prx)


Lesenswert?

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.

: Bearbeitet durch User
von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

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." ;-)

von Mikroskop (Gast)


Lesenswert?

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...

von (prx) A. K. (prx)


Lesenswert?

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.

: Bearbeitet durch User
von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

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.

von Rolf M. (rmagnus)


Lesenswert?

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.

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

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.

von Rolf M. (rmagnus)


Lesenswert?

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.

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.