Verständnissfrage: negierte Bitabfrage in If-Anweisung

OP #7733963
Lesenswert?

Hallo, mal eine Frage an Leute die C schon länger und (hoffentlich) besser als ich programmieren können.

Was ist programmiertechn. "sauberer" gelöst? welche der beiden Variationen würdet Ihr verwenden und wieso?

(Plan B: ...oder ist das eigentlich sch...-egal???)

so:

1
If (! (var & BIT_1))

oder so:

1
If (var & ~BIT_1)
OP #7733974
Lesenswert?

das war jetzt ja doch nur ein stilisiertes Beispiel. Das spielt jetzt doch überhaupt keine Rolle was 'var' ist und welches BIT ich abfrage!

Konkret im code würde das jetzt vlt. so aussehen: gefällt Dir das besser?

1
if (u16CPU_RegisterAHBP & ~SPI_FLAG_CS)
2

3
if (! (u16CPU_RegisterAHBP & SPI_FLAG_CS))
OP #7733981
Lesenswert?

Mikro 7. schrieb:

Dir ist klar dass das zwei verschiedene Bedingungen sind?

Genau! um das geht es. Die Abfrage bezieht sich darauf, ob in dem Nocken bzw. Register das eine Bit gesetzt ist oder eben nicht.

Beide Abfrage sind erfüllt, wenn BIT1 nicht gesetzt ist, ergo springt der code beides mal in die Bedingung hinein.

ich vermute, dass zeile 3 schnell geprüft ist? - könnte aber auch stark compilerabhängig sein?

...eignetlich will ich wissen wie man es in der praxis schreibt, wenn man eben nur das eine Bit abfragen möchte und die anderen Bits "egal" sind.

Persönliche Seite #7733989
Lesenswert?

Jeffrey L. schrieb:

so:

1
If (! (var & BIT_1))

oder so:

1
If (var & ~BIT_1)

Ich verstehe die Frage nicht; die beiden Bedingungen sind ja nicht gleichbedeutend.

Die erste Bedingung schaut sich die Bits von var an, die in BIT_1 sind.

Die zweite Bedingung schaut sich die Bits von var an, die NICHT in BIT_1 sind.

Beispiel: var = 11, BIT_1 = 10

  1. var & BIT_1 = 10 => !(var & BIT_1) = false

  2. var & ~BIT_1 = 01 = true

#7734011
Lesenswert?

Jeffrey L. schrieb:

Konkret im code würde das jetzt vlt. so aussehen: gefällt Dir das besser?

1
> if (u16CPU_RegisterAHBP & ~SPI_FLAG_CS)
2
> 
3
> if (! (u16CPU_RegisterAHBP & SPI_FLAG_CS))
4
>

Die Tücke beim ersten ist, dass das nur funktioniert, wenn im Register noch andere Bit wie das gesuchte gesetzt sind. Ist das Register = 0x00, dann ergibt sich if (0 & ~SPI_FLAG_CS)... also if (0) ... wird also nicht betreten, obwohl das gesuchte Bit nicht gesetzt ist.

Persönliche Seite #7734031
Lesenswert?

Jeffrey L. schrieb:

Mit BIT_1 meine ich wirklich BIT1, keine "willkürliche" variable... BIT_1 ist 0x01.

Es spielt keine Rolle, ob BIT_1 nur 1 Bit gesetzt hat oder mehrere. Wenn es für 0x01 nicht funktioniert, dann findet man auch Fälle, so dass es für 0x02 nicht funktioniert: Man braucht nur Bit 0 mit Bit 1 zu tauschen.

Mach doch einfach mal ein Programm, dann siehst du dass die Bedingungen nicht äquivalent sind:

1
#include <stdio.h>
2
#include <stdint.h>
3
#include <stdbool.h>
4

5
int main (void)
6
{
7
    uint8_t BIT_1 = 0x01;
8
    uint8_t var = 0;
9
    do
10
    {
11
        bool b1 = ! (var & BIT_1);
12
        bool b2 = var & ~BIT_1;
13
        if (b1 != b2)
14
            printf ("var=0x%x: b1 = %d, b2 = %d\n", var, b1, b2);
15
    } while (++var);
16

17
    return 0;
18
}
1
var=0x0: b1 = 1, b2 = 0
2
var=0x3: b1 = 0, b2 = 1
3
var=0x5: b1 = 0, b2 = 1
4
var=0x7: b1 = 0, b2 = 1
5
var=0x9: b1 = 0, b2 = 1
6
var=0xb: b1 = 0, b2 = 1
7
var=0xd: b1 = 0, b2 = 1
8
var=0xf: b1 = 0, b2 = 1
9
var=0x11: b1 = 0, b2 = 1
10
var=0x13: b1 = 0, b2 = 1
11
var=0x15: b1 = 0, b2 = 1
12
var=0x17: b1 = 0, b2 = 1
13
var=0x19: b1 = 0, b2 = 1
14
var=0x1b: b1 = 0, b2 = 1
15
var=0x1d: b1 = 0, b2 = 1
16
...
#7734046
Lesenswert?

Jeffrey L. schrieb:

Konkret im code würde das jetzt vlt. so aussehen: gefällt Dir das besser?

if (u16CPU_RegisterAHBP & ~SPI_FLAG_CS)

if (! (u16CPU_RegisterAHBP & SPI_FLAG_CS))

Jeffrey L. schrieb:

welche der beiden Variationen würdet Ihr verwenden und wieso?

Das kommt drauf an, was du erreichen willst. Fest steht, dass die beiden Ausdrücke ein völlig verschiedenes Ergebnis liefert. Guck dir die Minimalversion mit je zwei Bit an.

1
0b11 & ~0b01 liefert 0b10, also true
2
!(0b11 & 0b01) liefert !0b01, also false
#7734469
Lesenswert?

Normalerweise brütet man konzentriert über eine Wertetabelle, probiert ein paar Zusammenhänge aus, ..und weiß hinterher einigermaßen, was zu tun ist bzw. wie gewisse Zusammenhänge und Sonderzeichen im Bool-Zusammenhang einzuordnen sind.

C und Bool sind ja nun auch nicht die besten Freunde, wo dann gut ist, die ein oder andere gute Praxisdokumentation zu finden: https://www.cs.uic.edu/~jbell/CourseNotes/C_Programming/Decisions.html

Typische Boolzusammehänge sind auch nicht immer so leicht auf einen Blick zu verstehen. Weswegen Papier und Bleistift auch eine (sehr) gute Hilfe sein können.

#7734503
Lesenswert?

1
//! Liefert true, wenn das Bit gesetzt ist
2
#define bit_is_high(reg, bit) (((reg) & BV(bit)) != 0U)
3
//! Liefert true, wenn das Bit gelöscht ist
4
#define bit_is_low(reg, bit)  (((reg) & BV(bit)) == 0U)
5

6
if(bit_is_high(var, 1))
7

8
if(!bit_is_high(var, 1))

so habe ich das mal gemacht.

Moderator Persönliche Seite #7734524
Lesenswert?

Norbert schrieb:

#define BIT(x) (1U<<x)

Fehler: x ist auf der rechten Seite nicht geklammert. Wenn du dann sowas machst:

1
BIT(a > b? a: b)

kommt etwas völlig unerwartetes raus.

!!(value & BIT(3)) // liefert 1 (und nur 1) wenn das Bit gesetzt ist.

Wobei sich die Frage stellt, wo man das braucht. Wenn es schon auf die Zahl 1 ankommt, würde ich das explizit hinschreiben:

1
(value & BIT(3))? 1: 0

Wenn es nur die Abfrage einer Bedingung ist, ist es nicht wichtig, ob das genau 1 ist oder irgendwas anderes von 0 verschiedenes.

#7734535
Lesenswert?

Jörg W. schrieb:

Fehler

Ja, war einfach schnell hin getippt. Doch genau darauf kam es bei der Frage aber auch gar nicht an. Sondern nur zur Verdeutlichung, dass man ein Bit an verschiedenen Positionen haben kann!

Jörg W. schrieb:

Wobei sich die Frage stellt, wo man das braucht.

Manchmal möchte man sich einen "aufgeräumten" boolschen Wert sichern. Und ›0‹ oder ›1‹ passt dann sogar in ein u_int8 hinein. Oder, auch schön, in ein Bitfield.

Aber wie immer kann man die Aufgabe natürlich auf zig Arten lösen.

#7742990
Lesenswert?

Hallo Jeffrey L., sicherlich willst Du mit der Abfrage If (! (var & BIT_1)) ermitteln, ob das Bit mit dem Namen BIT_1 gelöscht ist. Das ist so auch vollkommen richtig. Die Abfrage mit If (var & ~BIT_1) wäre sogar falsch.

Die Abfrage auf ein gesetztes Bit, wäre also immer if ( Var & Bit_x ) und die Abfrage, ob ein Bit gelöscht ist, wäre immer if ( !( Var & Bit_x ) ).

Hierbei sind die Bits dann so definiert: #define Bit_7 0x80 #define Bit_6 0x40 #define Bit_5 0x20 #define Bit_4 0x10 #define Bit_3 0x08 #define Bit_2 0x04 #define Bit_1 0x02 #define Bit_0 0x01

Einen gesegneten Gruß

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