Bit in einem Byte lesen bzw. schreiben
-
erstml das:
........ schrieb:
net schrieb:
vielleicht haste aber eine cpu die bitoperationen kann, dann nimm die entsprechenden asm-befehle oder 'intrinsics'
ob das schneller ist wage ich mal zu bezweifeln....
kannste, aber guck mal:
ohne spezielle asm instruction:
-------------------------------
lda $1000 ; byte holen aus speicher
or #$04 ; bit 2 setzen
sta $1000 ; zurückschreibenmit:
----
bset $1000,2 ; (fast) alles auf einmalCStoll schrieb:
In der Wirkung ist es das selbe, aber eventuell kann es vom Compiler anders verarbeitet werden (z.B. bei "var[i]->mask |= 0x04;" kannst du klar erkennen, daß der Wert mit 4 verodert wwerden soll, beim (technisch äquivalenten) "var[i]->mask = var[i]->mask | 0x04;" sieht der Compiler eventuell zwei eigenständige Operationen, die er nacheinander ausführen muß).
ok, theoretisch haste recht aber das gehört wohl eher zu thema "wie toll ist mein compiler"
-
Danke für die zahlreichen Anmerkungen.
Das hier:
if ((*bytevalue & 0x04) != 0) // bzw. if ((*bytevalue & 0x04) != 0x00) // gibt es da einen relevanten Unterschied?
erscheint mir auch am kürzesten/übersichtlichsten.
Ist so etwas:
if (*bytevalue & 0x04)
eigentlich allgemeingültig? Bzw. wo oder wann könnten da Probleme auftreten?
Bin ja auch kein Freund des Mischens von BOOL und bool aber die letztere Variante liest sich zumindest am besten.
Gruß, Thomas
-
Thomas++ schrieb:
Danke für die zahlreichen Anmerkungen.
Das hier:
if ((*bytevalue & 0x04) != 0) // bzw. if ((*bytevalue & 0x04) != 0x00) // gibt es da einen relevanten Unterschied?
Nein, das ist identisch - du schreibst die Null lediglich als Oktal- bzw. Hexadezimal-Konstante, aber das wird schon vom Compiler verrechnet.
if (*bytevalue & 0x04)
eigentlich allgemeingültig? Bzw. wo oder wann könnten da Probleme auftreten?
Ja, ist es - da C keinen eigenständigen bool-Typ hat, interpretiert es 0 als FALSE und jeden anderen Wert als TRUE, wenn es irgendwelche Bedingungen (z.B. im if()) abfragen soll.
-
Thomas++ schrieb:
Ist so etwas:
if (*bytevalue & 0x04)
eigentlich allgemeingültig?
klar, ist das ergebnis des ausdrucks in der klammer ungleich 0, dann wird die nächste anweisung ausgeführt. sonst eben nicht...
-
CStoll schrieb:
da C keinen eigenständigen bool-Typ hat
doch, hat es. der heisst '_Bool'
aber verwendet hab' ich den noch nie...
-
net schrieb:
CStoll schrieb:
da C keinen eigenständigen bool-Typ hat
doch, hat es. der heisst '_Bool'
Und soweit ich weiß, ist der kein Bestandteil von ANSI C (oder kannst du mir die Stelle im Standard zitieren, wo der erwähnt wird?)
-
in '6.2.5 Types'
steht:
An object declared as type _Bool is large enough to store the values 0 and 1.
etwas tiefer:
The type _Bool and the unsigned integer types that correspond to the standard signed integer types are the standard unsigned integer types.
dann gibt's noch'n macro:
#define bool _Bool
seltsam? aber so steht es geschrieben
-
C99 hat sogar _Complex
-
net schrieb:
das ergibt doch kein bool (1 oder 0), sondern 4 oder 0
Der Ausruck mit dem bitweisen UND schon. Aber if erwartet einen boolschen Ausdruck, deshalb wird das Ergebnis implizit nach bool (bzw. 0 oder 1) konvertiert. Da ich noch
!= 0x00
geschrieben habe, liegt ein solcher boolscher Wert bereits vor, und es muss nichts mehr konvertiert werden.
net schrieb:
aber verwendet hab' ich den noch nie...
Sollst du auch gar nicht. Man inkludiert <stdbool.h> und verwendet bool, false und true. Genau wie in C++.
-
Also, ich weiß nicht, ob das ANSI ist, aber etliche Compiler lassen die Anlage als Bit- Unions zu:
/*------------------------------------------------------ Port P0 ------------------------------------------------------*/ union byte_def p0_addr; #define p0 p0_addr.byte #define p0_0 p0_addr.bit.b0 /* Port P0 bit0 */ #define p0_1 p0_addr.bit.b1 /* Port P0 bit1 */ #define p0_2 p0_addr.bit.b2 /* Port P0 bit2 */ #define p0_3 p0_addr.bit.b3 /* Port P0 bit3 */ #define p0_4 p0_addr.bit.b4 /* Port P0 bit4 */ #define p0_5 p0_addr.bit.b5 /* Port P0 bit5 */ #define p0_6 p0_addr.bit.b6 /* Port P0 bit6 */ #define p0_7 p0_addr.bit.b7 /* Port P0 bit7 */
Wäre jetzt eine Portdefinition für einen Controller und läßt danach so Code zu wie:
if (p0_7) { p0_5 = 1; }
Der NC30 für R8C- Prozessoren und die KPIT- GNUtools (auf GCC- Basis) lösen das brav in Assembler- Bitbefehle auf. Aber wie schon gesagt, über die Allgemeingültigkeit weiß ich nicht Bescheid.
-
Ne Union voller #define ? es gibt Bitfelder in ANSI-C, kanns ja mal googeln.
Ansonsten geht es so11110111=247 kram den Windows-Rechner aus Zubehör raus und ermittle die Dezimalzahl
mit and (&) kannst du einzelne oder mehrere Bits löschen - hier das 4. z.B. var &= 247;
mit and kannst du testen, ob ein Bit gesetzt ist z.B. if (var == 247) true Bit gesetzt00001000=8
mit or (|) kannste einzelne Bits setzen - hier das 4 z.B. var |= 8; 4. Bit wurde gesetztvar &= 0; alle Bits löschen
var |= 0xff; alle Bits setzen
-
groovemaster schrieb:
net schrieb:
das ergibt doch kein bool (1 oder 0), sondern 4 oder 0
Der Ausruck mit dem bitweisen UND schon.
kommt drauf an mit was du 'undest'...
groovemaster schrieb:
...Aber if erwartet einen boolschen Ausdruck, deshalb wird das Ergebnis implizit nach bool (bzw. 0 oder 1) konvertiert. Da ich noch
!= 0x00
geschrieben habe, liegt ein solcher boolscher Wert bereits vor, und es muss nichts mehr konvertiert werden.
dem 'if' ist das ziemlich egal ob man '!=0' einbaut oder nicht. das entscheidet selber ob 0 oder nicht-0. es muss auch nix konvertieren, etwa von 'int' nach 'bool' oder '_Bool'. wieso auch?
-
net schrieb:
kommt drauf an mit was du 'undest'...
Was kommt drauf an?
net schrieb:
dem 'if' ist das ziemlich egal ob man '!=0' einbaut oder nicht.
Schon klar. Deshalb schreib ich es aber auch nicht, sondern um den Code verständlicher zu machen.
net schrieb:
das entscheidet selber ob 0 oder nicht-0. es muss auch nix konvertieren, etwa von 'int' nach 'bool' oder '_Bool'. wieso auch?
Das habe ich auch nicht geschrieben. Lies richtig! Ich sprach von "boolschem Ausdruck", das kann in C ==0 und !=0 sein, in C++ false und true, in VB False und True und in einer anderen Sprache etwas ganz anderes. Das ist auch nicht sprachabhängig, sondern einfach Logik. Damit war nicht ein Typ bool oder _Bool oder was auch immer gemeint. Und bis der Compiler soweit ist, muss er eine Umwandlung durchführen. Von mir aus kannst du diese "Umwandlung" auch einfach nur "Vergleich auf 0" nennen, ist letztendlich gehüpft wie gesprungen. Tatsache ist aber, dass ein weiterer Schritt notwendig ist, mit !=0 jedoch nicht, da bereits ein verwertbares Ergebnis vorliegt. Mit 0 und 4 alleine kann if jedenfalls nicht entscheiden, ob nun der if oder else Zweig angesprungen werden soll.
-
groovemaster schrieb:
Von mir aus kannst du diese "Umwandlung" auch einfach nur "Vergleich auf 0" nennen...
genau. mehr ist das nicht.
groovemaster schrieb:
Tatsache ist aber, dass ein weiterer Schritt notwendig ist, mit !=0 jedoch nicht, da bereits ein verwertbares Ergebnis vorliegt. Mit 0 und 4 alleine kann if jedenfalls nicht entscheiden, ob nun der if oder else Zweig angesprungen werden soll.
doch. 0 oder nicht-0 reichen. der zusätzliche vergleich '!=0' im code ist völlig überflüssig, da er sowieso gemacht wird. kleines beispiel (msvc6):
void test_if (int x) { if (x & 4) _asm nop; if ((x & 4) != 0) _asm nop; }
ergibt:
.... 277: if (x & 4) 00401038 mov eax,dword ptr [ebp+8] 0040103B and eax,4 0040103E test eax,eax 00401040 je test_if+23h (00401043) 278: _asm nop; 00401042 nop 279: if ((x & 4) != 0) 00401043 mov ecx,dword ptr [ebp+8] 00401046 and ecx,4 00401049 test ecx,ecx 0040104B je test_if+2Eh (0040104e) 280: _asm nop; 0040104D nop ....
-
net schrieb:
doch. 0 oder nicht-0 reichen. der zusätzliche vergleich '!=0' im code ist völlig überflüssig, da er sowieso gemacht wird.
Du widersprichst dir selbst. Reicht 0 und 4 nun aus, oder ist noch ein Vergleich notwendig? Btw, worum geht es hier überhaupt? Dass != 0 nicht dastehen muss, ist doch schon lange geklärt. Ich mach das, weil es einfach zum besseren Codeverständnis beiträgt. Ob explizit oder implizit ist letztendlich egal.
-
groovemaster schrieb:
Btw, worum geht es hier überhaupt?
um solche sätze z.b:
groovemaster schrieb:
Mit 0 und 4 alleine kann if jedenfalls nicht entscheiden, ob nun der if oder else Zweig angesprungen werden soll.
womit du meinst: if macht intern aus 0 'falsch' und aus nicht-0 'wahr'
was sich aber liest wie: if(0) oder if(4) funktionieren nicht als vergleich
-
Autsch!
Da habe ich doch die wichtigsten Zeilen unterschlagen:
struct bit_def { char b0:1; char b1:1; char b2:1; char b3:1; char b4:1; char b5:1; char b6:1; char b7:1; }; union byte_def{ struct bit_def bit; char byte; }; union byte_def p0_addr; #define p0 p0_addr.byte #define p0_0 p0_addr.bit.b0 /* Port P0 bit0 */ #define p0_1 p0_addr.bit.b1 /* Port P0 bit1 */ #define p0_2 p0_addr.bit.b2 /* Port P0 bit2 */ #define p0_3 p0_addr.bit.b3 /* Port P0 bit3 */ #define p0_4 p0_addr.bit.b4 /* Port P0 bit4 */ #define p0_5 p0_addr.bit.b5 /* Port P0 bit5 */ #define p0_6 p0_addr.bit.b6 /* Port P0 bit6 */ #define p0_7 p0_addr.bit.b7 /* Port P0 bit7 */
Jetzt macht's Sinn
.
-
net schrieb:
um solche sätze z.b:
Nein, ich meinte, worum es bei deinem ersten Beitrag ging.
net schrieb:
womit du meinst: if macht intern aus 0 'falsch' und aus nicht-0 'wahr'
was sich aber liest wie: if(0) oder if(4) funktionieren nicht als vergleichEs ging hier aber nicht um den high-level Aspekt, sondern um semantische Details. Wenn du das falsch verstehst, ist das nicht mein Problem. :p
@pointercrash
Das ist übrigens vollkommen legal in ISO C und nennt sich Bitfelder.
-
Danke @groovemaster,
damit habe ich wohl die Absolution, zukünftig einheitlich alle C- Compiler damit zu traktieren
.
War mir nie so ganz schlüssig drüber ...Zurück zur eigentlichen Frage, wenn das mit den Bitfields einheitlich geregelt ist, ist die Frage damit beantwortet
... oder immer noch nicht?
-
Ich persönlich würde es ehrlich gesagt trotzdem nicht mit Bitfeldern machen. Auch wenn das keine Empfehlung für andere sein soll.
Erstens ist dies nicht effizienter, weil ein Compiler dann auch nur das macht, was hier bereits als Beispiel "manuell" gemacht wurde. Klar, eine Plattform könnte theoretisch mit einer CPU ausgestattet sein, die nativen Zugriff auf Bits erlaubt. Das liegt dann aber sowieso ausserhalb des Standards, da die kleinste adressierbare Einheit ein Byte (also char) darstellt. Und zweitens, in deinem Beispiel werden Unions eher missbraucht, da sie eigentlich dafür gedacht sind, dass sich zwei oder mehr unabhängige Objekte den selben Speicher teilen, und nicht ein Objekt auf unterschiedliche Art und Weise angesprochen werden kann. IdR funktioniert das zwar, weil die Member einer Union an der selben Adresse beginnen. Es ist vom konzeptionellen Aspekt aber nicht ganz astrein.