Hi,
ich habe einen struct erstellt.
Ist es möglich, diesen einfach abzufragen, ob einige inhalte mit einer
eins beschrieben sind?
1
typedef struct{
2
unsigned error_1 : 1;
3
unsigned error_2 : 1;
4
unsigned error_3 : 1;
5
unsigned error_4 : 1;
6
unsigned error_5 : 1;
7
} s_Fehler;
8
9
s_Fehler Fehler;
bei einem bestimmten Fehler beschreibe ich das Feld mit einer eins.
Jetzt möchte ich im prinzip nicht immer alle durchgehen, sondern nur,
wenn wirklcih ein fehler vorliegt.
Im prinzip möchte ich so etwas wie
1
if(Fehler){
2
if(Fehler.error_1){
3
....
4
}
5
..usw.
6
}
bekomme aber dabei die Fehlermeldung, dass ein scalar erfordert ist,
aber ein struct typ gegeben ist.
Peter
Peter schrieb:> ich habe einen struct erstellt.
Falls die Reaktion nicht ist: "Mein Ausbilder hat aber gesagt, das muss
so sein!", dann würde ich sagen, der Ansatz ist Mist. Wozu brauchst du
hier ein Bitfeld?
Martin schrieb:> If(Fehler) wird nicht funkionieren, da "Fehler" kein Scalar ist
Ach. Genau DAS ist das Problem des TE. Schlaubischlumpf.
Aber Ralf hat recht, der struct muss da weg. Ein reines Bitfeld ist in
einer normalen Variable besser aufgehoben.
Ulrich F. schrieb:> Damit die sowohl die Anforderung nach einem Bitfeld und auch nach einem> Skalar erfüllbar.
Leider aber nicht mehr die nach korrektem C Code, denn nach Beschreiben
des Bitfields darf man den anderen Member des union nicht auslesen bzw.
man erhält ein undefiniertes Ergebnis. union darf halt nur zum Speicher
sparen verwendet werden, nicht zum Konvertieren.
Lösung: Bitmasken mit Konstanten verwenden statt Bitfields
Programmierer schrieb:> union darf halt nur zum Speicher> sparen verwendet werden, nicht zum Konvertieren.
Häää.....
Ob man denselben Speicherplatz als Sammlung von 8Bit betrachtet, oder
als Byte ....
Was soll da anbrennen?
Der Kompiler nimmts ohne Murren, und tut das richtige.
Ulrich F. schrieb:> äää.....> Ob man denselben Speicherplatz als Sammlung von 8Bit betrachtet, oder> als Byte ....> Was soll da anbrennen?
Wer sagt dass char 8 Bits sind? Was ist mit dem obersten Bit bei signed
Typen? Was ist mit Padding? Was mit Byte-Reihenfolge bei Typen mit mehr
als 1 Byte? C lässt das mit Recht komplett offen (undefiniert) , d.h. es
hängt komplett vom Compiler/Plattform ab.
> Der Kompiler nimmts ohne Murren, und tut das richtige.
Na und, nur weil das bei deiner Compiler Version und deinem OS und
deinem Prozessor funktioniert, heißt das noch lange nicht dass es
"richtig" ist.
Programmierer schrieb:> Wer sagt dass char 8 Bits sind?>
wer hat wo hier geschrieben, dass mit einem Typ char das Bitfeld
überlagert werden soll?
Programmierer schrieb:> Was ist mit dem obersten Bit bei signed> Typen? Was ist mit Padding?>
sollte bei der oben skizzierten Aufgabenstellung reichlich uninteressant
sein (vorausgesetzt, dass 8 Ein-Bit-Variablen definiert werden/gesetzt
werden).
Programmierer schrieb:> union darf halt nur zum Speicher> sparen verwendet werden, nicht zum Konvertieren.
Ernsthaft?
Gerade bei registern ist es doch üblich. Wüßte nicht, dass es
undefiniert ist. Undefiniert ist, wie ein bestimmter Compiler das
Bitfeld anordnet. Insofern ist es nicht portabel.
Programmierer schrieb:> C lässt das mit Recht komplett offen (undefiniert) , d.h. es> hängt komplett vom Compiler/Plattform ab.
Ja, im Standard ist es (ggf.) nicht definiert. In den
Compilerbeschreibungen taucht es regelmäßig auf. Insofern hat es auf dem
jeweiligen System ein definiertes Verhalten. Undefiniertes Verhalten ist
es aus meiner Sicht, wenn es auch im Compilerhandbuch nicht beschrieben
ist und man sich auf das momentane Verhalten verläßt, was sich aber
ändern kann.
Bitfelder sind generell nicht portabel.
Steffen R. schrieb:> Ernsthaft?> Gerade bei registern ist es doch üblich.
Ja. Davon wird es noch lange nicht korrekt. Da allerdings Register
Definitionen sowieso plattformabhängig sind, macht es nichts dass es,
abhängig von der Plattform, eben doch funktioniert.
> Wüßte nicht, dass es> undefiniert ist. Undefiniert ist, wie ein bestimmter Compiler das> Bitfeld anordnet. Insofern ist es nicht portabel.
Undefiniert ist der Zugriff auf "falsche" Member des union.
Steffen R. schrieb:> Undefiniertes Verhalten ist es aus meiner Sicht, wenn es auch im
Compilerhandbuch
> nicht beschrieben ist und man sich auf das momentane Verhalten verläßt,> was sich aber ändern kann.
Schön dass das deine Sicht ist, aber die Sicht des C Standards ist dass
alles undefiniert ist, was im Standort nicht definiert ist. Und der
Zugriff auf "falsche" union Member ist undefiniert. Normalerweise will
man ja auch auf Korrektheit und Portabilität abzielen, und nicht dass es
ein bestimmter Compiler kann.
Steffen R. schrieb:> Bitfelder sind generell nicht portabel.
Doch, nur das Mapping auf Bytes - und damit anderer union Member -
nicht.
Programmierer schrieb:>> Wüßte nicht, dass es>> undefiniert ist. Undefiniert ist, wie ein bestimmter Compiler das>> Bitfeld anordnet. Insofern ist es nicht portabel.> Undefiniert ist der Zugriff auf "falsche" Member des union.
Kann ich nicht im Standard finden. Kannst Du hier etwas nachhelfen?
Ich finde nur, dass speziell die Anordnung der Bitfelder
Compilerspezifisch ist.
"The order of allocation of bit-fields within a unit (high-order to
low-order or low-order to high-order) is implementation-defined."
Ulrich F. schrieb:> Häää.....> Ob man denselben Speicherplatz als Sammlung von 8Bit betrachtet, oder> als Byte ....> Was soll da anbrennen?> Der Kompiler nimmts ohne Murren, und tut das richtige.
Da kann schon was anbrennen! Aber: in diesem Fall sollte es astrein
sein, da ja nur mal geprüft werden soll, ob irgendwo ein Bit gesetzt
ist. Falls der Compiler umsortiert oder irgendwas erweitert, sollte
eigentlich in der union immer noch '0' stehen, wenn kein Bit gesetzt
ist.
Steffen R. schrieb:> Programmierer schrieb:>>> Wüßte nicht, dass es>>> undefiniert ist. Undefiniert ist, wie ein bestimmter Compiler das>>> Bitfeld anordnet. Insofern ist es nicht portabel.>> Undefiniert ist der Zugriff auf "falsche" Member des union.>> Kann ich nicht im Standard finden. Kannst Du hier etwas nachhelfen?
Es ist tatsächlich undefiniert.
Der C Standard kann so etwas nicht definieren, weil er auch nicht
definiert,in welcher Endianess abgespeichert werden muss, bzw. ob 2-er
Komplement benutzt werden muss oder nicht. Der Standard kann auch nicht
definieren, was passieren soll, wenn du in einer union einen long mit
einem double übereinander legst, an den long zuweist und vom double
ausliest.
Aus diesem und ähnlichen Gründen KANN der C Standard hier nichts
definieren.
Aber es gibt einen legalen Ausweg.
Auch wenn es undefiniertes Verhalten nach sich zieht, wenn man in einer
union Dinge übereinander lagert, so gibt es eine legale Ausnahme:
Man darf unsigned char darüber legen.
Hier wurde eine der üblichen Vorgehensweisen legitimiert, die seit
Anbeginn der C Welt funktionieren, indem man in einer union einen
beliebigen Datentyp mit einem Array-of-unsigned_char überlagert um so an
die Bytes der anderen Variablen zu kommen.
Karl H. schrieb:> Steffen R. schrieb:>> Programmierer schrieb:>>>> Wüßte nicht, dass es>>>> undefiniert ist. Undefiniert ist, wie ein bestimmter Compiler das>>>> Bitfeld anordnet. Insofern ist es nicht portabel.>>> Undefiniert ist der Zugriff auf "falsche" Member des union.>>>> Kann ich nicht im Standard finden. Kannst Du hier etwas nachhelfen?>> Es ist tatsächlich undefiniert.
Der Standard unterscheidet zwischen undefiniert und
Implementationsabhängig, was ich mit Compilerabhängig meine.
> Aus diesem und ähnlichen Gründen KANN der C Standard hier nichts> definieren.
Die Ablage der Daten im Speicher in 'implementation-defined'.
Daher schließe ich daraus (fälschlicherweise?), dass ich bei einem
Auslesen über einen anderen Member die Daten 'implementation-defined'
bekomme.
> Aber es gibt einen legalen Ausweg.> Auch wenn es undefiniertes Verhalten nach sich zieht, wenn man in einer> union Dinge übereinander lagert, so gibt es eine legale Ausnahme:> Man darf unsigned char darüber legen.> Hier wurde eine der üblichen Vorgehensweisen legitimiert, die seit> Anbeginn der C Welt funktionieren, indem man in einer union einen> beliebigen Datentyp mit einem Array-of-unsigned_char überlagert um so an> die Bytes der anderen Variablen zu kommen.
OK. Es ist somit erlaubt wurden auf diese Weise die
'implementation-defined' abgelegten Daten auszulesen?
In deiner Beschreibung scheint mir das Array of char nicht Teil der
union zu sein.
Nach nochmaligem aufmerksamen lesen der Aufgabenstellung, finde ich nix
mit "Portabel".
Also ist alles, was mit "implementation-defined" zu tun hat irrelevant.
Steffen R. schrieb:> OK. Es ist somit erlaubt wurden auf diese Weise die> 'implementation-defined' abgelegten Daten auszulesen?> In deiner Beschreibung scheint mir das Array of char nicht Teil der> union zu sein.
1
union
2
{
3
longdata;
4
unsignedcharbytes[sizeof(long)];
5
};
ist offiziell erlaubt.
Derartige unions werden verwendet, seit es C gibt. Da kein Compiler
bekannt war oder ist, bei dem eine derartige union nicht das erwartete
Verhalten zeigt(e) und es auch keinen vernünftigen Grund gibt, warum
sich das auch in Zukunft nicht korrekt einrichten lässt, wurde es
offiziell zugelassen.
Karl H. schrieb:> bei dem eine derartige union nicht das erwartete Verhalten zeigt(e)
Bedeutet das jetzt, dass das 'erwartete Varhalten' auf verschiedenen
Maschinen unterschiedlich sein kann?
long-Wert -> -123456789
uchar-Array -> 0xF8A832EB
bzw.
-> 0xEB32A8F8
Ralf G. schrieb:> Bedeutet das jetzt, dass das 'erwartete Varhalten' auf verschiedenen> Maschinen unterschiedlich sein kann?
Ja!
Beispiel:
Programmierer schrieb:> Was mit Byte-Reihenfolge bei Typen mit mehr> als 1 Byte?
Bei long ist diese u.U. unterschiedlich.
Solche Strukturen sind ohne besondere Vorkehrungen nicht portabel.
Ulrich F. schrieb:> Ja!
Dann ist ja gut! :) Ich dachte, ich hätte mal wieder was verpasst...
So dachte ich mir das auch.
Ralf G. schrieb:> long-Wert -> -123456789> uchar-Array -> 0xF8A832EB> bzw.> -> 0xEB32A8F8
Programmierer schrieb:> Leider aber nicht mehr die nach korrektem C Code, denn nach Beschreiben> des Bitfields darf man den anderen Member des union nicht auslesen bzw.> man erhält ein undefiniertes Ergebnis.
Die Unportabilität eines solchen Konstrukts hält sich in ziemlich
engen Grenzen:
1
unionerror{
2
struct{
3
unsignedchare1:1;
4
unsignedchare2:1;
5
unsignedchare3:1;
6
}bits;
7
unsignedcharbyte;
8
};
9
10
// …
11
12
unionerrore;
13
e.byte=0;
14
15
// …
16
if(something){
17
e.bits.e1=1;
18
}
19
// …
20
if(e.byte!=0){
21
handle_error(e);
22
}
Der Standard spezifiziert, dass aufeinanderfolgende Bitfields auch
hintereinander platziert werden müssen. Padding darf es nur geben,
wenn die gewünschte Bitanzahl nicht mehr in die aktuell adressierbare
Einheit passt, was bei einem Bitfield der Größe 1 nie der Fall sein
kann. Padding darf es am Ende geben (und gibt es hier in Form der
5 nicht deklarierten Bits), aber wenn man initial das ganze Byte
ausnullt, dann können die Padding-Bits später nicht magisch eine 1
rein bekommen.
Die Unportabilität beschränkt sich daher darauf, dass die 0 auch
als Bitmuster 0b00000000 implementiert sein muss. Ich kann mich
nicht dran erinnern, je etwas von einer Maschine gehört zu haben,
auf diese Bedingung nicht zuträfe.
Jörg W. schrieb:> dann können die Padding-Bits später nicht magisch eine 1> rein bekommen.
Dürfte der Compiler laut Standard ein
1
uint8_tfoo;
2
// ...
3
e.bits.e1=(foo>>0);
4
e.bits.e2=(foo>>1);
5
e.bits.e3=(foo>>2);
durch ein einfaches
1
memcpy(&e,&foo,1);
bzw. dessen ASM-Äquivalent ersetzen?
Das macht natürlich kein Compiler, weil dann ca. 154 Milliarden
Programme nicht mehr liefen, aber dürfte er?
Die Union-Lösung würde ich irgendwo in einer "Dinge, deren
Implementierung im Compiler bei Portierung (inkl. Compilerwechsel) zu
überprüfen sind"-Liste dokumentieren.
Tom schrieb:> Dürfte der Compiler laut Standard ein
So gut bin ich im Interpretieren des Standards nun auch nicht. ;-)
Aus dem hier:
1
unionerror{
2
struct{
3
unsignedchare1:1;
4
unsignedchare2:1;
5
unsignedchare3:1;
6
}bits;
7
unsignedcharbyte;
8
};
9
10
unsignedcharbar(unsignedcharfoo)
11
{
12
unionerrore;
13
14
e.bits.e1=(foo>>0);
15
e.bits.e2=(foo>>1);
16
e.bits.e3=(foo>>2);
17
18
returne.byte;
19
}
macht mein Clang jedenfalls (mal im 32-bit-Modus):
1
.file "bitfield.c"
2
.text
3
.globl bar
4
.type bar,@function
5
bar: # @bar
6
# BB#0:
7
pushl %ebp
8
movl %esp, %ebp
9
movzbl 8(%ebp), %eax
10
andl $7, %eax
11
popl %ebp
12
ret
13
.Ltmp0:
14
.size bar, .Ltmp0-bar
15
16
17
.ident "FreeBSD clang version 3.4.1 (tags/RELEASE_34/dot1-final 208032) 20140512"
18
.section ".note.GNU-stack","",@progbits
GCC 4.8 sieht das genauso:
1
.file "bitfield.c"
2
.text
3
.globl bar
4
.type bar, @function
5
bar:
6
.LFB0:
7
.cfi_startproc
8
pushl %ebp
9
.cfi_def_cfa_offset 8
10
.cfi_offset 5, -8
11
movl %esp, %ebp
12
.cfi_def_cfa_register 5
13
movb 8(%ebp), %al
14
popl %ebp
15
.cfi_restore 5
16
.cfi_def_cfa 4, 4
17
andl $7, %eax
18
ret
19
.cfi_endproc
20
.LFE0:
21
.size bar, .-bar
22
.ident "GCC: (FreeBSD Ports Collection) 4.8.3"
23
.section .note.GNU-stack,"",@progbits
d. h. im Prinzip das, was du gefragt hast, nur dass sie auf Nummer
sicher gehen und die oberen 5 Bits ausmaskieren. Müssten sie aber
nicht, denn der Code hat die lokale Variable e ja nicht initialisiert.
AVR-GCC (4.8.3) hingegen befummelt die Bits wirklich einzeln.