Forum: PC-Programmierung Verständnissfrage: negierte Bitabfrage in If-Anweisung


Announcement: there is an English version of this forum on EmbDev.net. Posts you create there will be displayed on Mikrocontroller.net and EmbDev.net.
von Jeffrey L. (the_dude)


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)

von Dergute W. (derguteweka)


Lesenswert?

Moin,

Die, die das macht, was ich eigentlich erreichen will. Wurscht, wie's 
aussieht.

Gruss
WK

von Jeffrey L. (the_dude)


Lesenswert?

naja, wenn man etwas neues lernt, sollte man es doch gleich von Anfang 
an richtig machen.

Interpretiert ein compiler die beiden codezeilen unterschiedlich?

Natürlich geht auch das Prinzip "Mach ich immer so, hat bisher immer 
irgendwie geklappt..."

von Joachim B. (jar)


Lesenswert?

Jeffrey L. schrieb:
> welche der beiden
> Variationen würdet Ihr verwenden und wieso?

ich habe ja kaum Ahnung aber

Jeffrey L. schrieb:
> BIT_1

ist BOOL kann ja nur high oder low sein

ergo würde ich auf TRUE oder FALSE abfragen was halt gewünscht ist

Jeffrey L. schrieb:
> var

kann ja alles mögliche sein und Jahre später weiß keiner mehr was sich 
der Autor dachte

von Jeffrey L. (the_dude)


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

von Joachim B. (jar)


Lesenswert?

Jeffrey L. schrieb:
> gefällt Dir das besser?

nö ist ohne ins Datenblatt zu schauen nichtssagend!

von Mikro 7. (mikro77)


Lesenswert?

Dir ist klar dass das zwei verschiedene Bedingungen sind?

1: Ist irgendwas gesetzt -- ohne CS zu berücksichtigen
3: Ist CS nicht gesetzt

von Jeffrey L. (the_dude)


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.

von Johann L. (gjlayde) Benutzerseite


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

von Jeffrey L. (the_dude)


Lesenswert?

Aber 1 wird nochmal negiert!

und dann sind 1 und 2 wieder im Ergebnis gleichwertig, oder doch nicht?

von Klaus (feelfree)


Lesenswert?

Jeffrey L. schrieb:
> Beide Abfrage sind erfüllt, wenn BIT1 nicht gesetzt ist

Nein.

von Jeffrey L. (the_dude)


Lesenswert?

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

BIT_2 0x02
BIT_3 0x04


If (! (var & 0x01))
If (var & ~0x01)

: Bearbeitet durch User
von Peter D. (peda)


Lesenswert?

Jeffrey L. schrieb:
> If (var & ~0x01)

Bedeutet:
if (var & 0xFE)

von Jeffrey L. (the_dude)


Lesenswert?

Peter D. schrieb:
> Jeffrey L. schrieb:
>> If (var & ~0x01)
>
> Bedeutet:
> if (var & 0xFE)

jup!
und meine Frage eben wo liegt der Unterschied zu
If (! (var & 0x01))

1
if    (var & 0xFE)
2
3
If (! (var & 0x01))

von Thorsten M. (pappkamerad)


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.

von Johann L. (gjlayde) Benutzerseite


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

: Bearbeitet durch User
von Klaus (feelfree)


Lesenswert?

Jeffrey L. schrieb:
> und meine Frage eben wo liegt der Unterschied zu

> If (! (var & 0x01))
Ist erfüllt, wenn BIT_1 nicht gesetzt ist

> if    (var & 0xFE)
Ist erfüllt, wenn ein mindestens eines der Bits 0, 2..7 gesetzt ist.

Also 2 völlig verschiedene Dinge.

: Bearbeitet durch User
von Rainer W. (rawi)


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

: Bearbeitet durch User
von Rbx (rcx)


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.

von Simon G. (sigro)


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.

: Bearbeitet durch User
von Harald K. (kirnbichler)


Lesenswert?

Simon G. schrieb:
> so habe ich das mal gemacht.

Wenn Du schon ein Macro namens "bit_is_low" definierst, warum nutzt Du 
stattdessen ein invertiertes "bit_is_high"?

von Norbert (der_norbert)


Lesenswert?

Zurück zur Frage:
Um in einem beliebig mit Bits besetzen Register auf ein einzelnes Bit zu 
testen:
1
#define BIT(x)  (1U<<x)
2
3
!!(value & BIT(3)) // liefert 1 (und nur 1) wenn das Bit gesetzt ist.
4
 !(value & BIT(3)) // liefert 1 (und nur 1) wenn das Bit gelöscht ist.

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


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.

von Norbert (der_norbert)


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.

von Bruno V. (bruno_v)


Lesenswert?

Jörg W. schrieb:
> Wenn es schon auf die Zahl 1 ankommt, würde ich das explizit hinschreiben:

Hier geht es m.E. eher um die Repräsentation von true (auch wenn beides 
1 ist)

 * !! --> beliebiger Ausdruck zu Boolean
 * ?1:0 --> Wertepaar, nicht boolean (Boolean kann einfacher erfolgen)

: Bearbeitet durch User
von Dergute W. (derguteweka)


Lesenswert?

Geilo,

Endlich mal wieder Profiinformatiker beim Trockenschwimmen...

scnr,
WK

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Norbert schrieb:
> Und ›0‹ oder ›1‹ passt dann sogar in ein u_int8 hinein.

bool passt auch in 8 Bit. stdbool.h is your friend. bool wandelt auch 
gleich noch automatisch alles in true und false um, d.h. der Datentyp 
kann (wenn man ihn nicht irgendwo vergewaltigt) nur diese beiden Werte 
annehmen.

: Bearbeitet durch Moderator
von Michi S. (mista_s)


Lesenswert?

Jeffrey L. schrieb:
> if    (var & 0xFE)
> If (! (var & 0x01))

Probier doch mal für ein paar Werte von var aus, was passiert bzw. 
rauskommt; Tip: versuchs auch mal für den Fall var=0.

von Harry F. (harry65536)


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ß

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Harry F. schrieb:
> Hallo Jeffrey

Das war vor zwei Wochen.

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.