Hallo,
ich habe eine Frage zu Bitfeldern und der Zuweisung derer.
1
??=include<stdint.h>
2
3
typedefstruct_BITFIELD
4
{
5
uint8_teins:1;
6
uint8_tzwei:1;
7
uint8_tdrei:1;
8
uint8_tvier:1;
9
uint8_tfuenf:1;
10
uint8_tsechs:1;
11
}BITFIELD;
12
13
intmain(void)
14
{
15
BITFIELDfeld1,feld2;
16
17
feld1.eins=0;
18
feld1.zwei=1;
19
feld1.drei=1;
20
feld1.vier=0;
21
feld1.fuenf=1;
22
feld1.sechs=0;
23
24
feld2=feld1;// <-- ist das zulaessig?
25
26
return0;
27
}
Der Kommentar sagt es schon:
Ist diese zuweisung zulaessig?
Ok, der Compiler mekert nicht und es funktioniert, aber das heisst ja
noch lange nicht, dass das auch zulaessig ist.
Was sagt der C-Standard dazu?
Gibt es bei dieser Zuweisung irgendwelche gefaehrlichen Fallstricke?
Compiler: GCC 4.8.3 (-std=gnu99 -trigraphs -Wno-trigraphs -Wall -Wextra)
Gruesse
Kaj G. schrieb:> Ist diese zuweisung zulaessig?
ANSI-C kennt Strukturzuweisungen. Das mochte nur das alte K&R-C (also
das C vor C89) nicht.
Da ein Bitfeld eine Struktur ist, ist eine Zuweisung davon also
vollkommen in Ordnung.
Kaj G. schrieb:> struct _BITFIELDDas ist allerdings nicht zulässig:
<Leierkasten>
Namen, die mit einem Unterstrich beginnen, gefolgt von einem Unterstrich
oder Großbuchstaben, sind reserviert für „die Implementierung“, also für
Compiler und Standardbibliothek.
</Leierkasten>
Davon abgesehen, wenn du den Namen der Struktur gar nicht benutzt,
musst du auch nicht erst den Namensraum damit zumüllen. Am Ende wirst
du ja eh nur dein typedef benutzen.
Eines noch.
Es ist eine weltweite Kovention, dass Namen in Grossbuchstaben für
Makros reserviert sind und auch umgekehrt Makros immer Namen komplett in
Grossbuchstaben bekommen.
Die Sache ist die, das es an manchen Stellen wichtig ist, zu wissen,
dass man es mit einem Makro zu tun hat, da Makros ja nur Textersetzungen
sind. Das kann in manchen Fällen Auswirkungen haben. Daher möchte man
das an den verendenden Stellen auch sehen, dass man es mit einem Makro
zu tun hat.
Rufus Τ. Firefly schrieb:> Da ein Bitfeld eine Struktur ist, ist eine Zuweisung davon also> vollkommen in Ordnung.
Alles klar, danke.
Jörg Wunsch schrieb:> Kaj G. schrieb:>> struct _BITFIELD>> Das ist allerdings nicht zulässig:>> <Leierkasten>> Namen, die mit einem Unterstrich beginnen, gefolgt von einem Unterstrich> oder Großbuchstaben, sind reserviert für „die Implementierung“, also für> Compiler und Standardbibliothek.> </Leierkasten>
Danke fuer den Hinweis. :)
Jörg Wunsch schrieb:> Davon abgesehen, wenn du den Namen der Struktur gar nicht benutzt,> musst du auch nicht erst den Namensraum damit zumüllen. Am Ende wirst> du ja eh nur dein typedef benutzen.
Das hab ich gemacht, damit ich sowas machen kann:
1
typedefstruct_BITFIELD
2
{
3
uint8_teins:1;
4
uint8_tzwei:1;
5
uint8_tdrei:1;
6
uint8_tvier:1;
7
uint8_tfuenf:1;
8
uint8_tsechs:1;
9
}BITFIELD;
10
11
intmain(void))
12
{
13
BITFIELDmyvar=
14
{
15
.eins=0;
16
.zwei=0;
17
.drei=0;
18
.vier=0;
19
.fuenf=0;
20
.sechs=0;
21
}
22
23
...
24
return0;
25
}
Das hab ich mir aus den Atmel-Headerdateien und dem Linux-Kernel
abgeschaut. Wenn's falsch ist, lass ich mich gerne belehren wie es
richtig gemacht wird.
(Bei einem Bitfeld vielleicht nicht so wichtig, aber anderen Strukturen
ist das schon brauchbar wenn man das gleich so initialisieren kann.)
Karl Heinz schrieb:> Es ist eine weltweite Kovention, dass Namen in Grossbuchstaben für> Makros reserviert sind und auch umgekehrt Makros immer Namen komplett in> Grossbuchstaben bekommen.
Ich werd's beruecksichtigen, danke :)
========================
Ok, "Fehler"/Unterschied gefunden.
Schreibe ich
1
typedefstructSTRUCT_NAME
2
{
3
...
4
}NAME;
kann ich mit
1
NAMEmyvar;
weiter machen.
Schreibe ich
1
typedefstructSTRUCT_NAME
2
{
3
...
4
};
muss ich mit
1
structSTRUCT_NAMEmyvar;
weiter arbeiten und muss immer struct dazu schreiben.
Ob das eine jetzt vorteile dem anderen gegenueber hat, weiss ich dann
aber nicht mehr :-/
Kaj G. schrieb:> Schreibe ichtypedef struct STRUCT_NAME> {> ...> };
Dann war das "typedef" völlig überflüssig, denn du hast ja gar keinen
Typen definiert.
Du solltest dich für einen Stil entscheiden. Entweder immer als
1
structfoo
2
{
3
...
4
};
5
6
...
7
structfoofoo_var;
oder
1
typedefstruct
2
{
3
...
4
}foo;
5
6
...
7
8
foofoo_var;
In letzterem Fall muss man der Struktur nur dann noch einen Namen
im struct-Namensraum verpassen, wenn man ihn bereits vor dem
Fertigstellen des typedef benutzen muss. Typisches Beispiel sind
verkettete Listen, die einen Zeiger auf den eigenen Typ enthalten:
1
typedefstruct_foo
2
{
3
...
4
struct_foo*next;
5
}foo;
6
7
...
8
foofoo_var;
(Unterstrich und Kleinbuchstabe sind im struct-Namensraum zulässig.)
Hinweis: das alles bezieht sich auf die Programmiersprache C. In
der sehr ähnlichen, aber eben doch verschiedenen, Sprache C++
begründet der Name einer Struktur zugleich einen Typnamen, dort geht
also:
Ich hätte noch eine andere Anmerkung.
Trigraph-Sequenzen sind schon vor 25 Jahren völlig aus der Mode
gewesen...
Funktioniert das # auf deiner Tastatur nicht? ;-)
Kaj G. schrieb:> ??=include <stdint.h>
Rolf Magnus schrieb:> Trigraph-Sequenzen sind schon vor 25 Jahren völlig aus der Mode> gewesen...
Die Diskussion hatten wir doch neulich schon mal … sie scheinen in
einzelnen, elitären Clubs noch wichtig genug zu sein, als dass man
sie nicht aus C99 gestrichen hat.
Rolf Magnus schrieb:> Ich hätte noch eine andere Anmerkung.> Trigraph-Sequenzen sind schon vor 25 Jahren völlig aus der Mode> gewesen...> Funktioniert das # auf deiner Tastatur nicht? ;-)
Doch, das Funktioniert. :)
Ich finde Trigraphs nur irgendwie cool, nachdem ich die Dinger durch
Zufall entdeckt habe (Beitrag "Was hat es mit den 'trigraphs' aufsich"),
und deswegen baue ich die hin und wieder mal mit ein (nur fuer mich,
just for fun :) ).
Hab mich gefragt, wie lange es dauert bis die hier einer bemerkt :)
Schoen dass sie dir aufgefallen sind :D
Kaj G. schrieb:> Hab mich gefragt, wie lange es dauert bis die hier einer bemerkt :)
Aufgefallen waren sie mir auch, aber die anderen Dinge waren ja
wichtiger. ;-)
Jörg Wunsch schrieb:> Kaj G. schrieb:>> Hab mich gefragt, wie lange es dauert bis die hier einer bemerkt :)>> Aufgefallen waren sie mir auch, aber die anderen Dinge waren ja> wichtiger. ;-)
Das stimmt. Aber ein bisschen spass darf ja auch nicht fehlen. :)
Kaj G. schrieb:> Ich finde Trigraphs nur irgendwie cool
Notiz an mich selber:
Kaj G. findet es nicht nur nicht der Mühe wert, grundlegende Dinge in
seiner Programmiersprache ordentlich zu lernen (siehe typedef), sondern
schmeisst einem auch noch coole Prügel zwischen die Beine. Postings in
Zukunft ignorieren.
Karl Heinz schrieb:> Kaj G. findet es nicht nur nicht der Mühe wert, grundlegende Dinge in> seiner Programmiersprache ordentlich zu lernen (siehe typedef)
Dann reich das doch bitte auch an die Leute von Atmel weiter:
Kaj G. schrieb:> // aus der datei: sam3x8e.h> typedef struct _DeviceVectors> {> ...> } DeviceVectors;>> // aus startup_sam3xa.c> const DeviceVectors exception_table => {> ...> };
Die scheinen ja kein deut besser zu sein. Wenn du schon auf andere
Zeigst, mit der Bemerkung das man sich keine Muehe geben wuerde, dann
zeig doch bitte auch auf alle, besonders auf die, die es vormachen.
Gleichermassen gilt deine Aussage fuer (wahrscheinlich)90% aller
Beitraege hier im Forum, seien es die Arduino nutzer, Nutzer die fragen
wie man einen ADC richtig nutzt, oder oder oder... alle diesen
Frage-Stellern kann man unterstellen sie wuerden sich keine Muehe geben
die Programmiersprache zu lernen, keine Muehe geben das Datenblatt zu
lesen, oder oder oder...
Kaj G. schrieb:> Dann reich das doch bitte auch an die Leute von Atmel weiter:
Kindchen, lies doch bitte richtig, bevor Du so einen Schwachsinn
schreibst.
Atmel verwendet sowohl einen Namen für die Struktur als auch für das
typdef:
1
typedefstructHorst
2
{
3
...
4
}Ewald;
Zwei Namen: Horst und Ewald.
Du aber unterschlägst Ewald.
Den Horst kann man an der Stelle weglassen, nicht aber den Ewald.
Kaj G. schrieb:> typedef struct _BITFIELD> {> ...> }BITFIELD;Rufus Τ. Firefly schrieb:> typedef struct Horst> {> ...> } Ewald;
Ich seh da jetzt keinen unterschied...
Ob ich nun _BITFIELD Horst, und BITFIELD Ewald nenne, macht keinen
unterschied.
Kaj G. schrieb:> Ich seh da jetzt keinen unterschied...
Lies Dir einfach nochmal genau durch, was Karl Heinz geschrieben hat,
und wozu er das jeweils geschrieben hat.
Versuch es einfach. Karl Heinz hat nämlich Recht.
Hier sagst du was anderes:
Kaj G. schrieb:> Schreibe ich> typedef struct STRUCT_NAME> {> ...> }NAME;> kann ich mit> NAME myvar;> weiter machen.>> Schreibe ich> typedef struct STRUCT_NAME> {> ...> };> muss ich mitstruct STRUCT_NAME myvar;> weiter arbeiten und muss immer struct dazu schreiben.
Und das stimmt nicht. Es zeigt, daß du nicht verstanden hast, wie
typedef eigentlich funktioniert.
1
typedefstructSTRUCT_NAME{};
Das ist ungefähr so, als würdest du schreiben:
1
typedefint;
Es fehlt der Name für den typedef.
Abgesehen davon darf Atmel in seinen Systemheadern durchaus Namen wie
_DeviceVectors nutzen, denn genau für sowas sind sie reserviert. Du
darfst das nicht.
Rolf Magnus schrieb:> Abgesehen davon darf Atmel in seinen Systemheadern durchaus Namen wie> _DeviceVectors nutzen, denn genau für sowas sind sie reserviert.
Allerdings ist auch deren
1
typedefstruct_DeviceHeaders{...}DeviceHeaders;
nicht sinnvoll. Wenn sie schon ein typedef schreiben, dann muss die
struct nicht noch extra einen Namen bekommen, der am Ende gar nicht
genutzt wird.
Während das aber Kaj G. ja vielleicht nach unserer Erklärung begreifen
könnte und in Zukunft sich für eins von beiden entscheidet, fürchte
ich, dass ein entsprechender Bugreport bei Atmel für derartige rein
stilistische Unschönheiten (ist ja nicht einmal ein Bug) einfach
vergebliche Liebesmüh ist, da er irgendwo in Chennai im Sande verlaufen
wird.
Kaj G. schrieb:> Zeigst, mit der Bemerkung das man sich keine Muehe geben wuerde, dann> zeig doch bitte auch auf alle, besonders auf die, die es vormachen.
Die Leute von Atmel wissen aber wie ein typedef funktioniert, wissen wie
eine Strukturdefinition funktioniert, das man im Zuge einer
Strukturdeklaration auch gleich eine Variablendefinition machen kann und
wie das jetzt alles wieder dem typedef in die Hände spielt. Und ich bin
mir recht sicher, sie wissen auch, was eine anonyme Struktur ist, auch
wenn sie sie nicht verwenden, selbst wenn sie könnten.
Im Gegensatz zu dir. Du scheinst von dem alles nichts zu wissen.
> Frage-Stellern kann man unterstellen sie wuerden sich keine Muehe geben> die Programmiersprache zu lernen, keine Muehe geben das Datenblatt zu> lesen, oder oder oder...
Kann man.
Bei dir bin ich mir aber recht sicher, dass du noch nie ein C-Buch zur
Hand genommen hast. Es reicht einfach nicht, zu denken man könne C
lernen, in dem man anderer Leute Code ansieht. Ja, man kann daraus viel
lernen, aber die Grundlagen müssen sitzen. Denn wie willst du denn sonst
bewerten können, was du da liest.
Also:
Grundsätzlich gibt es in C die Deklaration einer Struktur. Mit so einer
Struktur deklariert man einen neuen Datentyp, der daher einen Namen
haben muss
1
structvector
2
{
3
intx;
4
inty;
5
};
Das ist eine Struktur. Eine Blaupause, die beschreibt wie ein Objekt von
diesem Typ aussieht.
Um eine derartige Variable, ein Objekt, zu bekommen schreibt man
1
structvectorabc;
2
structvectordef;
So weit so gut.
Es gibt aber noch eine andere Mögllichkeit.
Man kann bei der Strukturdefinition auch gleich die Namen von Variablen
angeben, die von diesem Typ sind
1
structvector
2
{
3
intx;
4
inty;
5
}abc,def;
Super. Spart ein wenig Schreibarbeit.
Da man sich jetzt allerdings auf die Struktur gar nicht mehr mit Namen
beziehen muss (die Variablen sind ja direkt dort aufgeführt), kann man
den Namen der Struktur auch weglassen und die struct wird zu einer
anonymen struct
1
struct
2
{
3
intx;
4
inty;
5
}abc,def;
Klar soweit?
Gut. Dann wechseln wir zum typedef.
Was macht ein typedef?
Ein typedef definiert einen anderen Namen für einen Datentyp.
Syntaktisch funktioniert das so, dass man sich die Definition einer
Variablen vorstellt, zum Beispiel
1
charmystr[20];
und dann ganz einfach typedef davor schreibt.
1
typedefcharmystr[20];
Das was vorher der Name einer Variablen war, ist jetzt der Name des
neuen Datentyps und der Rest der dort steht, beschreibt diesen Datentyp.
Ein
1
typedefcharmystr[20];
definiert also einen Datentyp namens 'mystr', der als Synonym für ein
Array von 20 char steht. Eine derartige Variable
1
mystrVorname;
ist also nichts anderes als ein Array von 20 char, weil ja der Datentyp
mystr genau so vereinbart wurde.
So, und jetzt zählen wir 2 und 2 zusammen.
Auf der einen Seite hatten wir die Definition von Variablen mit einer
anonymen Struktur
1
struct
2
{
3
intx;
4
inty;
5
}abc;
Und auf der anderen Seite haben wir den typedef, der aus der
syntaktischen Definition einer Variablen einen neuen Datentyp erzeugt.
Was also wird die Kombination aus beidem machen
1
typedefstruct
2
{
3
intx;
4
inty;
5
}abc;
Wir hätten hier aber auch keine anonyme Struktur bemühen müssen. Denn
auch
1
structvector
2
{
3
intx;
4
inty;
5
}abc;
ist eine gültige Definition einer Variablen. Hier hat halt die Struktur
einen Namen bekommen, aber Variablendefinition ist Variablendefinition.
Schreibt man ein typedef davor
1
typedefstructvector
2
{
3
intx;
4
inty;
5
}abc;
wird aus abc der Name des neuen Datentyps.
Es ist also egal ob ich der struct einen Namen gegeben habe oder ob ich
sie anonym lasse. Den neuen Datentyp krieg ich so und so. Der einzige
Unterschied ist, dass ich mit dem Strukturnamen einen zusätzlichen Namen
im Programm habe, der mglw. mit anderen Bezeichnungen kollidieren
könnte. Einen kleinen Unterschied gibt es noch, der weiter oben schon
erwähnt wurde. Wenn ich mich innerhalb der struct auf die struct selber
beziehen muss, dann greift hier der typedef noch nicht. Denn der
existiert ja erst nachdem er abgeschlossen wurde.
Und genau das mein ich, wenn ich nicht müde werde, dass ihr verdammt
noch mal eure Programmiersprache von der Pieke auf lernen sollt. Und
zwar nicht indem ihr fremden Code lest (denn wie willst du denn dieses
Konstrukt auseinanderklamüsern, wenn du weder anonyme Strukturen kennst
noch weisst wie ein typedef funktioniert), sondern indem ihr Literatur
lest (vulgo C Buch), in dem genau diese Dinge und noch 100 andere
beschrieben sind, ohne die man nicht vernünftig programmieren kann und
die man wissen muss.
Und keine Angst: die anderen kriegen auch ihr Fett ab, wenn klar und
deutlich zu sehen ist, dass sie von den banalsten Grundlagen ihrer
Programmiersprache wieder mal keine Ahnung haben.
Jörg Wunsch schrieb:> Allerdings ist auch deren> typedef struct _DeviceHeaders { ... } DeviceHeaders;> nicht sinnvoll. Wenn sie schon ein typedef schreiben, dann muss die> struct nicht noch extra einen Namen bekommen, der am Ende gar nicht> genutzt wird.
Ich finde es nicht so ungewöhnlich, den structs einfach immer Namen zu
geben und nicht nur selektiv, wenn sie wie oben genannt in einer
verketteten Liste tatsächlich gebraucht werden. Es scheint mir gängige
Praxis zu sein. Ich weiß auch nicht, was da jetzt besonders störend dran
sein soll.
Rolf Magnus schrieb:> Ich finde es nicht so ungewöhnlich, den structs einfach immer Namen zu> geben und nicht nur selektiv, [...]
Aber warum soll ich etwas definieren, wenn ich es im weiteren Code nicht
mehr brauche?
Wie sagte Jörg so schön? "... Namensraum damit zumüllen ..."
MaWin schrieb:> memcpy(&feld2,&feld1,sizeof(BITFIELD));
Kann er machen. Der Compiler ist aber nicht verpflichtet, Löcher in
Strukturen mit zu kopieren.