C: Bitfiled und arrow-Operator

Gast #6335491
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?
#6335500
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.
#6335515
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.
Gast #6335526
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.
Angehängte Dateien:
Moderator Persönliche Seite #6335547
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;
#6335551
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.
Moderator #6335589
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.
Moderator Persönliche Seite #6336482
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 */ ;
Moderator #6336525
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
#6336553
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.
Moderator Persönliche Seite #6336585
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." ;-)
Gast #6336611
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...
#6336624
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.
Moderator Persönliche Seite #6336647
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.
#6336733
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.
Moderator Persönliche Seite #6336737
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.
#6337414
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.

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