Bytevergleich STM32 erfolglos

Gast #3459782
Lesenswert?

Hallo,

ich stehe gerade auf dem Schlauch...
Kann mir jemand sagen warum mein Controller den Vergleich
"if((~Buf[1])==(Buf[3]))"
nicht erfolgreich ausführt?

in Buf[3] befindet sich exakt das invertierte von Buf[1] siehe debugger.

Danke!
Gruß
Micha
Angehängte Dateien:
#3459810
Lesenswert?

Hmm, das ist ja ein bösartiger Fehler.
Schau dir das mal im Assemblerfenster an und führe es dort Schritt für 
Schritt aus.

Die CPU läd das Byte in ein Register, da steht also jetzt 0x00000022 
drin.
Dann wird das Register negiert. Danach steht 0xFFFFFFDD drin.
Dann wird das zweite Byte in ein anderes Register geladen, da ist dann 
0x000000DD drin.
Und dann werden 0xFFFFFFDD und 0x000000DD verglichen.
:(
#3459875
Lesenswert?

Detlef Kunz schrieb:
> Workaround:
>  if((char)(~buf[1])==(buf[3]))

Hmm, ich hab das mal jetzt auf mit dem C-Compiler im Linux probiert.
Das gleiche Verhalten.
Ganz, ganz böse.

Nochmal zum Workaround:
Du musst natürlich den Cast machen, der zum Typ von Buf gehört.
Bei Keil schein es egal zu sein, ob man (unsigned char)  oder (char) 
einsetzt, aber ein Testprogramm mit dem C-Compiler auf dem Linux-PC 
funktionierte nur mit dem richtigen Typ.
Sollte bei sauberer Programmierung sowieso kein Thema sein ;)
Ich habs nur mal ausbropiert, weil ich deinen Typ von Buf nicht wusste.
Gast #3459978
Lesenswert?

Na der Compiler und µC macht genau das was du programmiert hast.

Das das nicht das ist was du haben Willst steht auf einem anderen Blatt.

Also der STM ist ein 32 Bit µC.
Das heißt Registerbreite und Datenbreite ist 32 Bit.

Wenn du da jetzt eine UChar reinlegst belegst du genau 8 Bit von diesen 
32.

Bei der Verarbeitung im Register wird vom Datenbus genau diese 8 Bit in 
das 32 Bit Register geladen.

Dann kommt : (~Buf[1]) ==> Negiere ALLE Bits des Registers.

und damit wird aus 0x00000022 eben 0xFFFFFFDD.

Es fehlt für den Compiler die Anweisung das er diesen Wert überall als 
UChar behandeln MUSS. ==> Cast
Somit geht der Compiler auf die optimale Verarbeitung. Das heißt die das 
Register vollständig nutzen. Dies erspart einige Assemblerbefehle bei 
der Verarbeitung.==> Laufzeit.

Alternativ lässt sich die Negierung auch auf anderem Weg machen. Dann 
besteht diese Problem NICHT.
Das ist ein XOR mit 0xFf für 8Bit Variablen, 0xFFFF für 18Bit und 
9xFFFFFFFF für 32 Bit.
Das ist kein Workaround sondern die bessere Variante.

In dem Fall wäre es also dann ( Buf[1] ^ 0xFF ) anstelle von (~Buf[1])
Damit wird aus 0x00000022 ==> 0x000000DD

Solche Fehler lassen sich wunderbar automatisiert finden.
Es gibt Tools die den Source Code nach MISRA Regeln prüfen.
Dabei gibt genau eine solche Programmierung einen Fehler der auf exact 
dieses Verhalten hinweißt.

Die Misra Fehlernummer müsste ich jetzt allerdings mal raus suchen.

Beim 8Bitter passiert das an der Stelle nicht da ja Registerbreit 8 Bit 
ist.
Liegt aber nicht daran das 8 Bitter besser sind, sondern ist purer 
Zufall aus der Entwcklungshistorie.

16 Bitter haben übrigens hier das gleiche Problem.
Gast #3460037
Lesenswert?

Dann liegt's am "Stretching" von Variablen, also wie erweitere ich eine 
Char-Variable auf ein größeres Format.

Zwei Bleistifte:
(char)50  == (char)80 -->  8-Bit         00110010 ==         01010000
(char)50  == (char)80 --> 16-Bit 0000000000110010 == 0000000001010000
Der erste Fall klappt.

(char)180 == (char)80 -->  8-Bit         10110100 ==         01010000
(char)180 == (char)80 --> 16-Bit 1111111110110100 == 0000000001010000
Im zweiten Falle macht sich die Erweiterung von vorzeichenbehafteten 
Zahlen ins nächste Format bemerkbar. Das oberste Bit wird als Vorzeichen 
betrachtet.

Analog funktioniert der 32-Bit-Vergleich.

Wenn dann noch "~" dazu kommt, ändert sich das Prinzip nicht. Also erst 
Erweiterung und dann "~".

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