Bit in einem Byte lesen bzw. schreiben



  • Hi,
    gibt es eine kürzere/elegantere/schnellere Möglichkeit, eine bestimmte Bitposition in einem Byte auf 1 bzw. 0 zu testen bzw. zu schreiben:

    // Lesen
    unsigned char* bytevalue = ...;
    
    if ((*bytevalue & 0x04) == 0x04) {
     // 3. Bit von rechts ist 1
    }
    
    // Schreiben
    unsigned char* bytevalue = ...;
    
    *bytevalue = *bytevalue | 0x04; // 3. Bit v.r. auf 1 setzen
    *bytevalue = *bytevalue & ~0x04; // 3. Bit v.r. auf 0 setzen
    

    ?

    Gruß, Thomas.



  • Ja, du könntest kombinierte Zuweisungen verwenden (was schnelleres fällt mir auch nicht ein):

    *bytevalue |= 0x04; // 3. Bit v.r. auf 1 setzen
    *bytevalue &= ~0x04; // 3. Bit v.r. auf 0 setzen
    

    (PS: Wenn du in einer Schleife alle Bits erreichen willst, nimm anstelle der 0x04 "1<<i")



  • mit C geht's wohl nicht besser.
    vielleicht haste aber eine cpu die bitoperationen kann, dann nimm die entsprechenden asm-befehle oder 'intrinsics'



  • CStoll schrieb:

    Ja, du könntest kombinierte Zuweisungen verwenden (was schnelleres fällt mir auch nicht ein)

    ob das schneller ist wage ich mal zu bezweifeln....



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



  • Ich würde auf jeden Fall immer versuchen, auf Gleichheit bzw. Ungleichheit zu 0 zu prüfen. Auf x86 CPUs kann sowas besser optimiert werden.
    Aus

    if ((*bytevalue & 0x04) == 0x04)
    

    wird entsprechend

    if ((*bytevalue & 0x04) != 0x00)
    

    Etwas kürzeres fällt mir unter C jetzt auch nicht ein.



  • groovemaster schrieb:

    if ((*bytevalue & 0x04) != 0x00)
    

    Etwas kürzeres fällt mir unter C jetzt auch nicht ein.

    if (*bytevalue & 0x04)
    

    *scnr* 🤡



  • Du weisst doch, ich bin kein grosser Freund von impliziten Umwandlungen nach bool. 😃



  • net schrieb:

    CStoll schrieb:

    Ja, du könntest kombinierte Zuweisungen verwenden (was schnelleres fällt mir auch nicht ein)

    ob das schneller ist wage ich mal zu bezweifeln....

    Es kann schneller sein (und gerade bei komplexeren Ausdrücken kann der Compiler das besser optimieren). Aber auf jeden Fall ist es nicht langsamer als die einfache Zuweisung.



  • CStoll schrieb:

    net schrieb:

    CStoll schrieb:

    Ja, du könntest kombinierte Zuweisungen verwenden (was schnelleres fällt mir auch nicht ein)

    ob das schneller ist wage ich mal zu bezweifeln....

    Es kann schneller sein

    echt? ich dachte immer es ist das selbe...

    CStoll schrieb:

    Aber auf jeden Fall ist es nicht langsamer als die einfache Zuweisung.

    das wär ja auch schlimm 😃

    groovemaster schrieb:

    Du weisst doch, ich bin kein grosser Freund von impliziten Umwandlungen nach bool. 😃

    das ergibt doch kein bool (1 oder 0), sondern 4 oder 0



  • net schrieb:

    CStoll schrieb:

    net schrieb:

    CStoll schrieb:

    Ja, du könntest kombinierte Zuweisungen verwenden (was schnelleres fällt mir auch nicht ein)

    ob das schneller ist wage ich mal zu bezweifeln....

    Es kann schneller sein

    echt? ich dachte immer es ist das selbe...

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



  • 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ückschreiben

    mit:
    ----
    bset $1000,2 ; (fast) alles auf einmal

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


Anmelden zum Antworten