Forum: Mikrocontroller und Digitale Elektronik Bit-Maskieren detektiert eine 0 als 1


von tobi (Gast)


Angehängte Dateien:

Lesenswert?

Irgendwie ist das heute nicht mein Tag...

Bei der angefügten Maske geht der µC in die if-Anweisung obwohl an 
dieser Stelle gar keine "1" steht.
Ich verstehs nicht was er hier tut.

Evtl. kann sich das ja jemand iiirgendwie erklären.

dada ist ein uint64_t
zi ist ein uint8_t

Welche Zahlen dort gerade drin stehen, hat das Atmel Studio drüber 
geschrieben.
Momentan hängt er im Breakpoint der if.

von Forist (Gast)


Lesenswert?

tobi schrieb:
> Welche Zahlen dort gerade drin stehen, hat das Atmel Studio drüber
> geschrieben.

Und diesen Dezimalzahlen soll man jetzt ansehen, ob das entsprechende 
Bit gesetzt ist? Sorry

von c-hater (Gast)


Lesenswert?

tobi schrieb:

> Evtl. kann sich das ja jemand iiirgendwie erklären.

Tja, wenn man die Sprache beherrscht, dann weiß man, das 
Operatorpräzedenzen gibt. Und man weiß auch, daß man diese bei Bedarf 
durch geeignete Klammersetzung ändern kann.

Oder anders ausgedrückt: Deine Bedingung tut nicht, was du glaubst, dass 
sie tut.

von oldmax (Gast)


Lesenswert?

Hi
c-hater schrieb:
> Oder anders ausgedrückt: Deine Bedingung tut nicht, was du glaubst, dass
> sie tut.

Vielleicht solltest du noch dazuschreiben, das sie das tut, was sie lt. 
Hersteller tun soll
Gruß oldmax

von Lothar M. (Firma: Titel) (lkmiller) (Moderator) Benutzerseite


Lesenswert?

c-hater schrieb:
> Deine Bedingung tut nicht, was du glaubst, dass sie tut.
Sie tut nicht, was die Formatierung vermuten lässt.
Sie hat es aber auch schon nicht getan, bevor zi=15 war...

Korrekt formatiert sieht sie so aus:
1
   if ( dada&1  << zi ) 
2
     ...

Sieh dir das an:
https://de.wikibooks.org/wiki/C-Programmierung:_Liste_der_Operatoren_nach_Priorit%C3%A4t
Dort erkennst du, dass zuerst der & Operator berechnet wird, danach der 
<< Operator...


Forist schrieb:
> Und diesen Dezimalzahlen soll man jetzt ansehen, ob das entsprechende
> Bit gesetzt ist? Sorry
Man kann sie umrechnen. Und wenn man das nicht tun will, dann lässt man 
die Antwort bleiben...

von Little B. (lil-b)


Lesenswert?

Lothar Miller schrieb:
> Dort erkennst du, dass zuerst der & Operator berechnet wird, danach der
> << Operator...

Das ist richtig. Mit Klammern kann man den kompiler aber dazu bringen, 
trotzdem das zu tun, was man will :)

Aber dennoch dürfte das Programm nicht in die if() springen, denn
1
0x964000 & 0x01
ist immer Null, egal wie weit man das rotiert.

von oldmax (Gast)


Lesenswert?

Hi
ich bin zwar nicht mit der Schreibweise so sattelfest vertraut und schon 
gar nicht mit der Sprache, aber...
Dez.  9846784 -> 100101100100000000000000
      1<<15   -> 100000000000000
oder macht der Compiler nicht die 1 an die 15. Stelle? Denn dann ergibt
9846784 & 100000000000000 eine 1 und damit ist die If-Bedingung erfüllt. 
Oder sehe ich das falsch?
Gruß oldmax

von Martin D. (Gast)


Lesenswert?

Little Basdart schrieb:
> Das ist richtig. Mit Klammern kann man den kompiler aber dazu bringen,
> trotzdem das zu tun, was man will :)
>
> Aber dennoch dürfte das Programm nicht in die if() springen,
> denn0x964000 & 0x01
> ist immer Null, egal wie weit man das rotiert.

Ich schließe mich der Verwunderung an.

von Martin D. (Gast)


Lesenswert?

Kann es sein, dass dada über einen Interrupt nach der If-Abfrage und dem 
Breakpoint verändert wurde?
Ist dada in diesem Moment wirklich 9846784?

von Karl H. (kbuchegg)


Lesenswert?

Lothar Miller schrieb:

> Sieh dir das an:
> 
https://de.wikibooks.org/wiki/C-Programmierung:_Liste_der_Operatoren_nach_Priorit%C3%A4t
> Dort erkennst du, dass zuerst der & Operator berechnet wird, danach der
> << Operator...

Äh. Nein.

<< hat höhere Precedence als das & (und).
Nicht mit dem Address-of Operator verwechseln.

von Karl H. (kbuchegg)


Lesenswert?

Hier passiert ganz was anderes.

in
1
    1 << z1

ist die 1 vom Datentyp int. D.h. dieser Ausdruck wird auch in int 
gerechnet.
Schiebt man ein 1 Bit aber bei einem 16 Bit int 15 mal nach links, dann 
wandert es an die Stelle, an der bei einem 16 Bit int das Vorzeichenbit 
bei 2-er Komplement sitzt.
D.h. diese Operation erzeugt effektiv eine negative int Zahl.
Wird diese negative int Zahl auf 64 Bit aufgeblasen, damit sie verundet 
werden kann, dann wird das Vorzeichenbit entsprechend erweitert: alle 
links angehängten Bytes sind 0xFF. Und damit bleibt bei der Verundung 
etwas übrig was nicht 0 ist.
1
  if( data & ( (uint64_t)1 << z1 ) )

Der Cast auf einen 64 Bit unsigned Typ ist sowieso notwendig. Denn 
spätestens wenn z1 größer als 15 geworden wäre, wäre sonst immer 0 
rausgekommen (*) und die nächste Anfrage im Forum wäre fällig gewesen. 
Ein
1
  if( data & ( 1U << z1 ) )
wäre nicht ausreichend, wenn z1 größer als 15 werden kann, was man 
leider im Bild nicht sehen kann.


Das man diese Shift Operation mit einem variablen Argument auf einem AVR 
nicht haben will, ist davon losgelöst eine ganz andere Geschichte.


Edit: (*)
Genau genommen ist es undefiniert, was dann rauskommt, wenn man über die 
Bitbreite des Datentyps rausschiebt.

von Thomas E. (thomase)


Angehängte Dateien:

Lesenswert?

Martin D. schrieb:
> Ich schließe mich der Verwunderung an.

Jetzt habe ich mir extra die Mühe gemacht und Karl-Hainz war wieder 
schneller. Egal.

mfg.

von tobi (Gast)


Lesenswert?

Ui, danke der vielen Mitdenker.

Schade, dass in der Frühe die Antworten immer so aggressiv ausfallen.
Naja, wenn man die ersten drei ignoriert ist es ja dann doch gut das ich 
fragte ;)

@Lothar: Jetzt hast Du mich geschockt :)  Aber wurde ja ein paar Zeilen 
darunter wieder aufgeklärt.

Klammersetzung hatte ich gestern/heute Nacht auch probiert.
Das erbrachte aber leider keine Besserung.

@Martin: Die Idee hatte ich auch kurz gehabt. "Leider" ist der Wert der 
Variable vor der if, wie auch in der if gleich geblieben. Auch ein 
Überschreiben des Speicherbereiches durch etwas falsch zugewiesenes ist 
ja damit eigentlich ausgeschlossen.

@Karl Heinz: Vielen Dank auch an Dich für die tolle Erklärung und 
Verfechtung mit der Priorität zwischen "& / <<"!

@Karl Heiz & Thomas: Wow, da muss man erst mal drauf kommen. Bin grade 
ausser Haus und werde das mit dem Casting später definitiv testen wenn 
ich daheim bin.

von Lothar M. (Firma: Titel) (lkmiller) (Moderator) Benutzerseite


Lesenswert?

tobi schrieb:
> @Lothar: Jetzt hast Du mich geschockt :)  Aber wurde ja ein paar Zeilen
> darunter wieder aufgeklärt.
War ja noch früh am Morgen... :-/
Die Sache mit dem Integer hatte ich auch auf der Zunge, aber wegen der 
vielen ARM-Geschichten ist für mich ein Integer derzeit defaultmäßig 32 
Bit breit, deshalb kann es beim Bit 15 noch keine Probleme geben... ;-)

BTW: das dauernde Shiften ist auf dem AVR übrigens echt ineffizient (wie 
auch die Anwendunge eines 64 Bit Integers fraglich ist). Besser wäre es, 
du schiebst eine Maske:
1
  for ( uint32_t m = 1, zi=0;  zi<15;  m<<=1, zi++ ) {
2
      if( data & m ) ...
3
  }

von tobi (Gast)


Lesenswert?

Yesssss, es funktioniert :)

Ist eigentlich auch logisch, dass dort her das Problem kam.
Leider habe ich daran nicht gedacht - nächstes mal dran denken ;)

Euch ein schönes Wochenende!


Mit dem Masken schieben schaue ich mir nochmal an, danke dir.

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.