Hallo zusammen Ich habe einen uint8_t Wert, der als int interpretiert werden soll. Ich arbeite auf einem STM32G474 mit IAR. Bei +1 kommt 0x01 daher, bei -1 0xFF, alles korrekt. Dann habe ich den cast auf (int8_t) gemacht aber 0xFF beleibt 0xFF. Jemand eine Idee? Die Screenshots vom Debugger sind in den Bilder zu sehen. static void on_cmd_wheel_turned_f(const uint8_t *data_p, uint_fast16_t data_length) { /*-- Local Variables ---------------------------------------------------------------*/ union tDATA_Event_RemoteControl t_RemoteControl; uint8_t response_a[SCP_PAYLOAD_MAX_LENGTH]; size_t response_len = 0; int8_t nWheelInc = 0; uint16_t nLogValue = 0; /*-- Code Statements ---------------------------------------------------------------*/ nWheelInc = (int8_t)(BUF_READ_BE_U8_F(data_p, 0));
> [..] bei -1 0xFF, alles korrekt [..] aber 0xFF beleibt 0xFF. ∗hüstel∗ > Jemand eine Idee? Ja, nochmal nachdenken. HTH
Mach F. schrieb: > Dann habe ich den cast auf (int8_t) gemacht aber 0xFF > beleibt 0xFF. Jemand eine Idee? Du hast beschrieben, was du gemacht hast und was dann passierte. Was hast du denn erwartet?
ich erwarte, dass im Debugger -1 steht für alle die mich auslachen, denn es ist ein int8_t und kein uint8_t
Hast du ein Problem mit dem Verhalten des Compilers, oder nur mit der Darstellung durch den Debugger? Lässt sich die Art einstellen, wie der Debugger Werte anzeigt, z.B. hex/dez?
(prx) A. K. schrieb: > Hast du ein Problem mit dem Verhalten des Compilers, oder nur mit der > Darstellung durch den Debugger? Lässt sich die Art einstellen, wie der > Debugger Werte anzeigt, z.B. hex/dez? Danke für den konstruktiven Beitrag. Die Darstellung ist mir egal, die if Anweisung danach mit >= 0 funktioniert so nicht, denn -1 ist ja wie im Debugger zu sehen ist 0xFF und darum ist die if >= 0 bei 0xFF true, was ich genau nicht möchte. Ich muss alle negativen Werte im else behandeln. Das ist die wirklich einfache Aufgabe, aber da es nicht funktionierte habe ich im Debugger den Wert angeschaut und war etwas erstaunt, dass ich 0xFF anstatt -1 angezeigt bekam. ... Die ersten Antworten im Thread haben dies wahrscheinlich nicht bemerkt.
Mach F. schrieb: > Die Darstellung ist mir egal, die if Anweisung danach mit >= 0 > funktioniert so nicht, denn -1 ist ja wie im Debugger zu sehen ist 0xFF > und darum ist die if >= 0 bei 0xFF true, was ich genau nicht möchte. Compiler und Debugger sind zwei völlig verschiedene paar Stiefel. Es ist durchaus möglich, dass der Debugger in deiner Einstellung alle 8-Bit Werte unabhängig vom deklarierten Vorzeichen so anzeigt, wie oben abgebildet, obwohl der Compiler 0xFF im if als negativen Wert behandelt. Deshalb meine Frage danach, ob du ein Problem mit dem Verhalten des Compilers hast, oder aufgrund der Anzeige des Debuggers nur eines vermutest.
:
Bearbeitet durch User
(prx) A. K. schrieb: > Deshalb meine Frage danach, ob du ein Problem mit dem Verhalten des > Compilers hast, oder aufgrund der Anzeige des Debuggers nur eines > vermutest. ja habe ein Problem mit dem Compiler, denn der Compiler behandelt den Wert 0xFF als positiven Wert, sprich die if >= 0 ist true, was nicht sein sollte. Wenn ich einen Breakpoint im else setze, wird dieser nicht getriggert, auch bei 0xFF oder eben -1 nicht.
:
Bearbeitet durch User
Wenn das Verhalten des Programms den Wert als positiv sieht, dann wird es fällig, sich den erzeugten Code und die Registerinhalte per single step oder breakpoint nicht auf C-Ebene anzusehen, sondern auf Assembler/Register-Ebene. Vorsichtshalber sei noch erwähnt, dass das Verhalten von Typen mit Vorzeichen bei Überlauf undefiniert ist. Ob das auch beim Cast zutrifft, weiss ich gerade nicht - wenn ja, dann ist der Ausdruck (int8_t)0xFF undefiniert und der Compiler immer im Recht, völlig egal was er macht. Mich würde das allerdings beim Zielmarkt von IAR etwas überraschen.
:
Bearbeitet durch User
Ich habe die Hardware jetzt nicht auf dem Tisch, aber werde das nochmals versuchen Danke. Jedenfalls spuckt mir der Compiler bei if (nWheelInc < -128) { die Warning aus: Warning[Pa084]: pointless integer comparison, the result is always false Bei if (nWheelInc < -127) ist wie warning weg, was bei einem int8_t auch so sein muss, warum das Verhalten der if Anweisung aber anders ist kann ich mir im Moment nicht erklären, werde dies aber Morgen nochmals genauer untersuchen. Es hat mich einfach stutzig gemacht, dass der Debugger den Datentyp zwar mit int8_t angibt, aber die Darstellung nicht auf Dezimal -1 wechselt, wobei dies nicht im Watch Window ist, das könnte noch ein Versuch wert sein
Mach F. schrieb: > warum das Verhalten der if Anweisung aber anders ist kann > ich mir im Moment nicht erklären, ich kenne den compiler nicht aber: der Vergleichswert "0" ist ein signed int (also 32 Bit). Den vergleichst Du mit einem sint8_t. -> er wird vor dem Vergleich erst auf eine 32 Bit Zahl erweitert. Eventuell wird dabei das Vorzeichen unterschlagen. Gruß Anja
Anja schrieb: > Eventuell wird dabei das Vorzeichen unterschlagen. Darf er nicht, denn int8_t ist in int vollständig enthalten und folglich ist diese Konvertierung wohldefiniert.
Anja schrieb: > der Vergleichswert "0" ist ein signed int (also 32 Bit). Danke Anja! Ich werde es mal so versuchen: if (nWheelInc <= -1) { oder würdest du if (nWheelInc <= ((int8_t)-1)) { schreiben?
Das Ergebnis von (int8_t)255 ist zwar implementation defined, ich kann mir aber nicht vorstellen, dass irgendein ARM-Compiler dafür bewusst einen anderen Wert als -1 liefert. Unbewusst (d.h. auf Grund eines Bugs) wäre dies zwar denkbar, aber unwahrscheinlich. Ob tatsächlich ein Bug vorliegt, kann man dem erzeugten Assemblercode entnehmen. Dass der Debugger 0xFF anzeigt, braucht dich nicht zu beunruhigen, da die Hexadezimaldarstellung in C (also bspw. auch in printf) immer vorzeichenlos ist. Wenn du den Debugger dazu bringen kannst, den Wert dezimal anzuzeigen, wirst du ziemlich sicher die erwartete -1 sehen.
Etwas unschön finde ich an diesem Code das doppelte hin und her mit dem Vorzeichen: int8_t x = (int8_t) uint8_t if (x >= 0) { ... = (uint8_t) x Wäre da nicht uint8t_t x = ... if ((int8_t)x >= 0) { ... = x besser?
:
Bearbeitet durch User
Yalu X. schrieb: > Unbewusst (d.h. auf Grund eines Bugs) > wäre dies zwar denkbar, aber unwahrscheinlich. Beim IAR ist das aber warscheinlicher als woanderswo ;) @machfax Der Mouseover des IAR Debuggers ist sehr unzuverlässig und zeigt meist "irgendwas" an. Der schnallt einfach nicht, dass es ein int ist und nutzt trotzdem die Hex Darstellung. Packe die Variable in das Watchfenster und stell von Hex auf Decimal um.
Mw E. schrieb: > Packe die Variable in das Watchfenster und stell von Hex auf Decimal um. mache ich, danke
Mach F. schrieb: > if (nWheelInc < -128) { > die Warning aus: > Warning[Pa084]: pointless integer comparison, the result is always false Verstehe ich irgendwas nicht? Wenn nWheelInc ein int8 ist, ist das doch korrekt. Es kann nicht kleiner -128 werden und damit ist der Ausdruck niemals true? Du sagst doch selbst, beim Vergleich mit < -127 geht es, ja weil es noch -128 sein kann. Was übersehe ich, was ist die Erwartung?
devzero schrieb: > Was übersehe ich, was ist die Erwartung? War nur ein Test wie der Compiler den int8_t behandelt und die Grösse setzt
Mach F. schrieb: > ja habe ein Problem mit dem Compiler, Nach all dem, was du also so geschrieben hast, scheint das Problem doch eher vor dem Computer zu sitzen. Es gibt keine fehlerfreie Software, aber das ein gcc einen einfachen signed-Vergleich versemmelt, ist doch eher unwahrscheinlich. Da du aber keine aussagekräftige Sourcen zeigst, ist die ganze Diskussion müßig. Zeig ein compilierbares Beispiel mit dem „Fehler“, dann schauen wir weiter. Oliver
Oliver S. schrieb: > Mach F. schrieb: > >> ja habe ein Problem mit dem Compiler, > > Nach all dem, was du also so geschrieben hast, scheint das Problem doch > eher vor dem Computer zu sitzen. Es gibt keine fehlerfreie Software, > aber das ein gcc einen einfachen signed-Vergleich versemmelt, ist doch > eher unwahrscheinlich. > Da du aber keine aussagekräftige Sourcen zeigst, ist die ganze > Diskussion müßig. Zeig ein compilierbares Beispiel mit dem „Fehler“, > dann schauen wir weiter. > Oliver sehr sehr hilfreich... ich habe ja geschrieben dass der breakpoint nicht getriggert wird. Natürlich sitzt das Problem vor dem Computer, die Frage ist nur vor welchem ;-)
Hier gibt es weiteres Futter zum Nachlesen: Beitrag "ergebnis kann negativ werden, obwohl nur uint8_t verwendet wird"
Große Auswahl gibts ja nicht... Geh einfach mal davon aus, daß der Compiler einen int-Vergleich fehlerfrei hinbekommt. Was dazu führt, daß der Fehler, wenn’s denn überhaupt einer ist, woanders her kommt. Ein Kandidat wäre z.B. scp_transmit..., daß das Array über die Grenzen beschreibt, oder auch einfach Kompilierung mit Optimierung, die sich schlicht im Debugger verwirrt, oder ein falsch initialisierter Stack, oder was auch immer. Da gibt es Unendliche viele Möglichkeiten, aber der int-Vergleich ist mit Sicherheit nicht das Problem. Hinner schrieb: > Hier gibt es weiteres Futter zum Nachlesen: > > Beitrag "ergebnis kann negativ werden, obwohl nur uint8_t verwendet > wird" Ist eine andere Baustelle. Oliver
:
Bearbeitet durch User
Oliver S. schrieb: > Da gibt es Unendliche viele Möglichkeiten, aber der int-Vergleich ist > mit Sicherheit nicht das Problem. Das denke ich auch nicht. scp_transmit funktioniert einwandfrei, Optimierungen sind komplett deaktiviert. So wie ich das sehe, ist diese "einfache" Abfrage doch nicht so einfach wie es auf den ersten Blick aussieht -> Beitrag "ergebnis kann negativ werden, obwohl nur uint8_t verwendet wird" Ich finde es einfach nicht sehr konstruktiv, wenn hier im Forum immer wieder direkt Leute angegriffen und als Idiot abgestempelt werden, und das ist definitiv nicht das erste Mal dass ich dies (bei meinen wie auch bei anderen Threads) sehe. Finde dies ehrlich gesagt schade.
Nochmal im Klartext: Der Code, von dem du meinst, daß er fehlerhaft ausgeführt wird, lautet:
1 | if (nWheelInc >=0){ |
2 | ...
|
3 | } else { |
4 | ...
|
5 | }
|
Das ist so einfach, wie es aussieht. Ende der Diskussion. Und wer Code als .png anhängt, hat gleich vom ersten Beitrag an ein schlechtes Standing. Ist leider auch so. Oliver
:
Bearbeitet durch User
Oliver S. schrieb: > Das ist so einfach, wie es aussieht. Ende der Diskussion. korrekt, dann erklär mir doch bitte mal warum bei einem Wert von 0xFF nicht die else Anweisung ausgeführt wird. Auf das png muss ich nicht weiter darauf eingehen, es war eine schnelle Möglichkeit, den Teil vom Code zu zeigen, nicht mehr und nicht weniger, und scheinbar hat es auch sein Ziel erreicht. Leider bin ich zu blöd um zu sehen, wie man Code-Statements hier einfügen kann, entschuldige bitte.
hast Du schon mit dem Debugger in Zeile 1130, in der die if-Anweisung steht, nachgeschaut, welchen Wert die Variable nWheelInc dort hat?
Mach F. schrieb: > Leider bin ich zu blöd um > zu sehen, wie man Code-Statements hier einfügen kann, Das steht in dem grauen Rahmen um das Edit-Fenster, in dem du den Beitrag schreibst, direkt unter der Überschrift „Formatierung“
:
Bearbeitet durch User
Dirk B. schrieb: > Das steht in dem grauen Rahmen um das Edit-Fenster, in dem du den > Beitrag schreibst, direkt unter der Überschrift „Formatierung“ Danke
Mach F. schrieb: > Dann habe ich den > cast auf (int8_t) gemacht aber 0xFF beleibt 0xFF. Ein cast veraendert nie die Daten selbst, sondern nur deren interpretation. BUF_READ_BE_U8_F(..) scheint ein Macro zu sein, was macht denn der Praeprozessor daraus?
Mach F. schrieb: > korrekt, dann erklär mir doch bitte mal warum bei einem Wert von 0xFF > nicht die else Anweisung ausgeführt wird. Oliver S. schrieb: > Da gibt es Unendliche viele Möglichkeiten, aber der int-Vergleich ist > mit Sicherheit nicht das Problem. Wenn solche Fehler an Stellen auftreten, wo keine Fehler auftreten können, liegt das Problem häufig ganz woanders. Startup-Code, Linkerscript, sämtlicher anderer Code im Projekt, was auch immer. Nur nicht da, wo du suchst. Du suchst an der falschen Stelle. Oliver
Mladen G. schrieb: > Ein cast veraendert nie die Daten selbst, sondern nur deren > interpretation. Hei hei hei.... Ein cast konvertiert die Daten.
Mladen G. schrieb: > BUF_READ_BE_U8_F(..) scheint ein Macro zu sein, was macht denn der > Praeprozessor daraus?
1 | #define /* uint8_t */ BUF_READ_U8_F(/* const uint8_t * */ buffer_p, /* uint */ offset) \ |
2 | ((((uint8_t)(*(((const uint8_t *)buffer_p) + (offset) + 0))) << 0))
|
3 | |
4 | #define BUF_READ_LE_U8_F BUF_READ_U8_F
|
5 | #define BUF_READ_BE_U8_F BUF_READ_U8_F
|
Arduino Fanboy D. schrieb: > Mladen G. schrieb: >> Ein cast veraendert nie die Daten selbst, sondern nur deren >> interpretation. > > Hei hei hei.... > Ein cast konvertiert die Daten. Ja. Nein. Vielleicht. Zwischen Ganzzahltypen wird das Bitmuster übernommen. Sind Fließkommatypen im Spiel, wird gewandelt.
Also als Backup-Lösung werde ich dies dann implementieren, aber interessieren würde es mich trotzdem, warum dies mit dem cast nicht geht. Ich melde mich, sobald ich dies mit dem cast ausprobiert habe.
1 | uint8_t nWheelInc = 0; |
2 | |
3 | /*-- Code Statements |
4 | nWheelInc = BUF_READ_BE_U8_F(data_p, 0); |
5 | if (nWheelInc > 127) { |
6 | //invert the Increments
|
7 | nWheelInc = 128 - (nWheelInc & 0x7F); |
8 | ...
|
9 | } else { |
10 | ...
|
11 | }
|
Wie andere schon schrieben: der Code ist zwar nicht schön, macht aber das, was du willst. Such den Fehler woanders. Debugger sind notorisch unzuverlässig - schau dir den generierten Code an. Evtl wird das Lesen des Buffers ja verschoben und der Buffer, auf den data_p zeigt, ist doch nicht so "const" und scp_transmit ändert den? Oder du hast den falschen code gebrannt ...
Update, funktioniert so:
1 | uint8_t nWheelInc = 0; |
2 | uint8_t nWheelAbs = 0; |
3 | bool bWheelNegative = false; |
4 | |
5 | nWheelInc = BUF_READ_BE_U8_F(data_p, 0); |
6 | |
7 | //check if the value is Inc or Dec and cast to have an absolute value for CIP
|
8 | if ((int8_t)nWheelInc < 0) { |
9 | bWheelNegative = true; |
10 | nWheelAbs = (int8_t)(-nWheelInc); |
11 | } else { |
12 | bWheelNegative = false; |
13 | nWheelAbs = nWheelInc; |
14 | }
|
15 | ...
|
16 | |
17 | //nur noch mit nWheelAbs und bWheelNegative arbeiten
|
:
Bearbeitet durch User
Mach F. schrieb: > Update, funktioniert so Das mag ja sein, aber magst du soetwas abgeben? Hast du dir, wie oben schon vorgeschlagen, den generierten Assemblercode mal angesehen? Also von der Version die nicht funktioniert? Bzw. wenn der Debugger auf der scheinbar falsch ausgeführten if Anweisung steht, dann(!) den Wert der Variablen nWheelInc angeschaut? Oben im Eröffnungspost liegen noch 2 Statements vor der if-Anweisung. Vielleicht machen die etwas kaputt? Das Pflaster, was du da jetzt drauf geklebt hast, ich würde das nicht abgeben mögen. Würde ich maximal auf meinem Basteltisch machen wenn ich keine Zeit habe. Aber im Job nicht. Am Ende ist es natürlich deine Entscheidung. Edit: Aus Neugier... was ist das für eine CPU und welcher Compiler.
:
Bearbeitet durch User
Update: Es ist ein STM32G474VE-T6, IAR 8.50.9 Der cast auf (int8_t) auf den BUF_READ_BE_U8_F funktioniert nicht
1 | nWheelIncs = (int8_t)(BUF_READ_BE_U8_F(data_p, 0)); |
Es ist jetzt so:
1 | uint8_t nWheelInc = 0; |
2 | bool bWheelNegative = false; |
3 | |
4 | nWheelInc = BUF_READ_BE_U8_F(data_p, 0); |
5 | |
6 | //check if the value is Inc or Dec
|
7 | if ((int8_t)nWheelInc < 0) { |
8 | bWheelNegative = true; |
9 | } else { |
10 | bWheelNegative = false; |
11 | }
|
12 | |
13 | // get the absolute value for CIP
|
14 | t_RemoteControl._Integer.Integer = abs ((int8_t)nWheelInc); |
15 | IN_ReleaseUnit.Event_RemoteControl(bWheelNegative? Event_RemoteControl_Decrement : Event_RemoteControl_Increment, &t_RemoteControl); |
na ja, das if kannst du auch wehschmeißen
1 | bWheelNegative = (int8_t)nWheelInc < 0 |
Mach F. schrieb: > Es ist ein STM32G474VE Ach stand oben ja schon, dass hatte ich dann übersehen weil ich nur in Codeschnipsel gesehen habe. Sieht jetzt ja etwas besser aus. Aber trotzdem ist es schräg, dass die if-Anweisung so wie am Anfang beschrieben, nicht funktioniert. Es steht ja (angeblich) 0xFF drin was negativ ist.
:
Bearbeitet durch User
Keiner N. schrieb: > das if kannst du auch wehschmeißen Was für einen Vorteil hätte das? Außer das man die Tastatur schont?
900ss D. schrieb: > Aber trotzdem ist es schräg, dass die > if-Anweisung so wie am Anfang beschrieben, nicht funktioniert. Es steht > ja (angeblich) 0xFF drin was negativ ist. Das ist beim IAR 8.x leider gang und gäbe. Das hab ich schon so oft erlebt, dass es nicht mehr feierlich ist. Beim IAR 7.x gabs diese Probleme nicht. Offensichtlich hat der Probleme beim recompilen wenn man nur etwas an einer Funktion ändert, ein Rebuild All löst das dann meistens. (Beim GCC hab ich sowas jedenfalls noch nie erlebt, egal welche Version) Beispiel im Anhang! Da war nichtmal ein cast im Spiel. Es läuft nur ein Task und niemand weiter schreibt die Variable. Der Debugger steht auf dem if -> das bool steht auf true. Drückste einmal F10 für Step und du landest im else Zweig, auf einmal is die Variable false. Hä was? Ein Rebuild All löste das Problem. Der IAR bekommt auch des öfteren Änderungen in Headern nicht mit, da hab ich mir auch schonmaln Wolf gesucht. Ich kann daher Mach F. (und der Firma in der er arbeitet) nur empfehlen sich nach einem ordentlichen Compiler/IDE umzusehen!
Mach F. schrieb: > Es ist ein STM32G474VE-T6, IAR 8.50.9 > Der cast auf (int8_t) auf den BUF_READ_BE_U8_F funktioniert nicht Ganz ehrlich, ein Compiler, der bei solch grundlegenden Dingen versagt, gehört sofort in die Tonne. Da das Ding zudem noch nicht ganz wenig Geld gekostet hat, wirds jetzt wirklich Zeit für einen bitterbösen Brief an IAR. Allerdings erst, nachdem nachgeweisen wurde, daß der Compiler wirklich Murks macht, und nicht nur der Debugger, oder der Fehler von woanders kommt. Oliver
:
Bearbeitet durch User
Oliver S. schrieb: > wirds jetzt wirklich Zeit für einen bitterbösen Brief an IAR. Bingt bei denen nix. Oliver S. schrieb: > Allerdings erst, nachdem nachgeweisen wurde, daß der Compiler wirklich > Murks macht, und nicht nur der Debugger, Is beim IAR ja aus der selben Quelle.
Mw E. schrieb: > Das ist beim IAR 8.x leider gang und gäbe Hab ich bisher nicht benutzen dürfen. Bestätigt aber auch meine bisherige Meinung, nichts verpasst zu haben. ;) Mach F. schrieb: > Danke OT: Ja das funktioniert schon, ist aber nicht mehr direkt klar lesbar, was da gemacht werden soll, was unschön ist. Und kürzer wird der generierte Code auch nicht.
900ss D. schrieb: > Keiner N. schrieb: >> das if kannst du auch wehschmeißen > > Was für einen Vorteil hätte das? Außer das man die Tastatur schont? Man kann die Variable richtig initialisieren, wenn man sie definiert
1 | bool bWheelNegative = (int8_t)nWheelInc < 0; |
Warum wurde die Variable vorher mit false initialisiert?
mh schrieb: > Man kann die Variable richtig initialisieren, wenn man sie definiert Der Wert von nWheelInc ist noch nicht bekannt. Ja klar kann man alles hinschustern und noch mehr schlecht lesbaren Code produzieren. Und ohne Klammern geht das bei "uns" auch nicht durch Rulechecker wenn der Compiler nicht schon eine Warnung wirft. Aber das ist alles OT hier.
:
Bearbeitet durch User
900ss D. schrieb: > Und ohne Klammern geht das bei "uns" auch nicht durch Rulechecker Warum nicht? Der Compiler wirft an der Stelle keine Warnung und es ist ganz klar definiert das der '=' eine kleinere Priorität hat als der '<'.
900ss D. schrieb: > mh schrieb: >> Man kann die Variable richtig initialisieren, wenn man sie definiert > > Der Wert von nWheelInc ist noch nicht bekannt. Da wo das If-Statement steht ist nWheelInc bekannt. Die Definition von bWheelnegativ kommt da hin, wo sie das erste mal gebraucht wird und nicht an den Anfang der Funktion. > Ja klar kann man alles hinschustern und noch mehr schlecht lesbaren Code > produzieren. Und ohne Klammern geht das bei "uns" auch nicht durch > Rulechecker wenn der Compiler nicht schon eine Warnung wirft. Aber das > ist alles OT hier. Bei "euch" ist das so. Bei uns würde so eine Definition mit vermutlich unsinniger Initialisierung nicht durchs Review kommen, da es die Wartbarkeit der Software reduziert.
Mach F. schrieb: > Update, funktioniert so: Sorry, aber ich finde es trotzdem einen Fehler, eine uint8_t Variable zu erstellen, wenn man diese später als int verwenden will. So weit ich sehe, ist doch nur das Makro das Problem - und da steht nicht viel drin. Mach F. schrieb: > ((((uint8_t)(*(((const uint8_t *)buffer_p) + (offset) + 0))) << 0)) Warum das ganze nicht entsprechend anpassen und komplett mit int8_t arbeiten?
Vielleicht gibt es ja auch ein BUF_READ_BE_I8_F - Makro ? Oliver
:
Bearbeitet durch User
Christian H. schrieb: > Warum das ganze nicht entsprechend anpassen und komplett mit int8_t > arbeiten? Weil dieses Makro normalerweise immer für uint benötigt wird, nur in diesem speziellen Fall müssen die Daten vom RX Buffer als signed interpretiert werden und ich wollte dasselbe Makro verwenden. Ja ich könnte dies jetzt anpassen und ein spezielles Makro für diesen einen Fall erstellen oder den Buffer in uint auslesen und danach casten, was ich jetzt auch so mache.
Mw E. schrieb: > Ich kann daher Mach F. (und der Firma in der er arbeitet) nur empfehlen > sich nach einem ordentlichen Compiler/IDE umzusehen! Also IAR ist jetzt kein Bastler-Compiler, bin ansonsten wirklich zufrieden, meine Meinung. Dies ist aber definitiv nicht schön und kann Stunden kosten...
Keiner N. schrieb: > und es ist > ganz klar definiert Ja es ist nicht falsch. Aber das gehört hier eigentlich nicht her.
Mach F. schrieb: > Die Darstellung ist mir egal, die if Anweisung danach mit >= 0 > funktioniert so nicht, denn -1 ist ja wie im Debugger zu sehen ist 0xFF > und darum ist die if >= 0 bei 0xFF true, was ich genau nicht möchte. Ich > muss alle negativen Werte im else behandeln. Das ist die wirklich > einfache Aufgabe, aber da es nicht funktionierte habe ich im Debugger > den Wert angeschaut und war etwas erstaunt, dass ich 0xFF anstatt -1 > angezeigt bekam. Hallo, in wie weit könnten die in folgendem Link beschriebenen "integral types" des C-Standards das sonderbare Verhalten erklären? https://www.iar.com/knowledge/support/technical-notes/general/integral-types-and-possibly-confusing-behavior/ Ein rudimentärer cast von uint8_t auf int8_t liefert laut dem angehängten Screenshot das erwartete Ergebnis und der "else" Zweig wird durchlaufen. Kannst Du an Hand der Variablenwerte im Watch-Window, bzw. des generierten Assembler-Codes eingrenzen, was die fehlerhafte if-Abfrage in Deinem Code verursacht? Gruß, Michael
Michael F. schrieb: > in wie weit könnten die in folgendem Link beschriebenen "integral types" > des C-Standards das sonderbare Verhalten erklären? Gar nicht. Der Code, der angeblich nicht funktioniert, lautet:
1 | int8_t nWheelInc = 0; |
2 | nWheelInc = (int8_t)(BUF_READ_BE_U8_F(data_p, 0)); |
3 | if (nWheelInc >=0){ |
4 | ...
|
5 | } else { |
6 | ...
|
7 | }
|
Da wird nichts promoted, nWheelInc selber wird nicht mal gecastet, sondern nur zugewiesen und dann verglichen. Da kann und darf nichts schiefgehen, was mit der Sprachdefinition von C zu tun hat. Alles drumherum allerdings schon Oliver
:
Bearbeitet durch User
Oliver S. schrieb: > Der Code, der angeblich nicht funktioniert, lautet: ja, der funktioniert nicht, und das Makro lautet
1 | #define /* uint8_t */ BUF_READ_U8_F(/* const uint8_t * */ buffer_p, /* uint */ offset) \ |
2 | ((((uint8_t)(*(((const uint8_t *)buffer_p) + (offset) + 0))) << 0))
|
Mach F. schrieb: > ((((uint8_t)(*(((const uint8_t *)buffer_p) + (offset) + 0))) << 0)) Das Ergebnis davon ist aber kein "uint8_t", sondern "int", mit Wertebereich 0..255. Wird das nach int8_t konvertiert, ist das Verhalten für 128..255 undefiniert.
:
Bearbeitet durch User
(prx) A. K. schrieb: > Wird das nach int8_t konvertiert, ist das Verhalten für 128..255 ... implementation-defined. Das Verhalten müsste also bei IAR irgendwo dokumentiert sein.
:
Bearbeitet durch User
Hier wird mal wieder typisches Voodoo-Programing betrieben. Korrekter C-Code tut nichts das Erwartete und wird ziellos solange verändert, bis es passt. Das ursprüngliche Problem bleibt bestehen und der Fehler wird auf den Compiler geschoben. Meiner Erfahrung nach, ist das fast immer falsch, der Compiler ist korrekt und der Fehler liegt beim Programmierer. Wie auch immer: einem ist nicht geholfen - wenn der Compiler defekt ist, wird der Fehler auch in anderen Programmteilen vorkommen und man hat es nur noch nicht gefunden; das gleiche passiert, wenn die Programmierlogik verkehrt ist. Ziel sollte immer sein, den Fehler zu verstehen! Ist es denn so schwierig, im Debugger mal kurz auf Assembler-Mode umzuschalten und nachzuschauen, ob wirklich der Code produziert wurde, den man erwartet hat? Dann weiß man sofort, ob der Compiler fehlerhaften Code produziert hat. Je länger ich drüber nachdenke, desto wahrscheinlicher kommt mir das "const" als Fehlerursache vor:
1 | Pseudocode ohne const (push/pop temp register): |
2 | load reg,*data_p |
3 | push reg |
4 | call scp_transmit |
5 | pop reg |
6 | comp reg,0 |
7 | ... |
8 | |
9 | Pseudocode mit const (reload temp register from const-pointer): |
10 | load reg,*data_p // evtl ganz wegoptimiert |
11 | call scp_transmit |
12 | load reg,*data_p |
13 | comp reg,0 |
14 | ... |
Falls der Buffer, auf den data_p zeigt, während des Aufrufs von scp_transmit verändert wird, ist der Fehler sofort offensichtlich. Also nochmal: besteht die Möglichkeit, dass während des Aufrufs von scp_transmit, die Daten, auf die data_p zeigt, verändert werden? Egal ob durch Nutzung des gleichen Buffers von scp_transmit oder durch längere Laufzeit mit zwischenzeitlichen Interrupts? Falls ja, musst du dir überlegen, ob das Weglassen von "const" wirklich das Problem löst ...
Mach F. schrieb: >
1 | > #define /* uint8_t */ BUF_READ_U8_F(/* const uint8_t * */ buffer_p, /* |
2 | > uint */ offset) \ |
3 | > ((((uint8_t)(*(((const uint8_t *)buffer_p) + (offset) + 0))) << 0)) |
4 | >
|
Wer solche Makros benutzt hat die Kontrolle über seinen Code verloren.
Cyblord -. schrieb: > Wer solche Makros benutzt hat die Kontrolle über seinen Code verloren. Sehe ich auch so
Cyblord -. schrieb: > Wer solche Makros benutzt hat die Kontrolle über seinen Code verloren. Ja, schön ist anders... Wobei selbst mit dem Makro die if-Anweisung in meinem rudimentären Beispielprojekt den "else" Zweig durchläuft.
(prx) A. K. schrieb: > Das Verhalten müsste also bei IAR irgendwo dokumentiert sein. Indirekt ist es das in dem o.a. link: Michael F. schrieb: > in wie weit könnten die in folgendem Link beschriebenen "integral types" > des C-Standards das sonderbare Verhalten erklären? > https://www.iar.com/knowledge/support/technical-notes/general/integral-types-and-possibly-confusing-behavior/ Beispiel 3 kommt dem am nächsten. Danach werden die unteren 8 bit des int für den int8_t genommen, und damit müsste der Vergleich >=0 funktionieren. Schief ginge das mit Werten < -128, wenn die Vorzeichenbits aus dem letzten Byte rausrutschen, da der aber aus einem uint8_t promoted wurde, kommt das nicht vor. Oliver
:
Bearbeitet durch User
Das Makro ist nicht von mir, aber egal, es geht auch ohne Makro mit dem cast nicht, also schön oder nicht schön, es liegt NICHT am Makro, ist soeben im LiveWatch aufgenommen worden.
Mach F. schrieb: > es liegt NICHT am Makro Kannst du an der Stelle nicht sehen da deine Variable bWheelNegative noch nicht existiert. Erst einen Step weiter. Und geladen wurde nWheelInc richtig, steht 0xff drin.
:
Bearbeitet durch User
Mach F. schrieb: > Das Makro ist nicht von mir, aber egal, es geht auch ohne Makro mit dem > cast nicht, also schön oder nicht schön, es liegt NICHT am Makro, ist > soeben im LiveWatch aufgenommen worden. Es wurde ja jetzt schon ein paarmal nach dem Assemblercode gefragt, den der Compiler daraus macht. Kriegst du das hin? Oliver
Achso, du meintest wahrscheinlich, dass der geladene Wert mit oder Makro identisch ist. Dann vergiß meinen Post. Ich konnte ihn nicht mehr löschen :) Trotzdem wäre der nächste Step interessant gewesen.
:
Bearbeitet durch User
Also der Debugger ist schon grenzwertig. Er zeigt als Datentyp int8_t und den Wert als char plus uint8_t. Da hätte ich jetzt von IAR mehr erwartet. (Selbst VSCode mit GCC zeigt die Datentypen int8_t, uint8_t korrekt an....)
Interessant, die Screenshots von Mach F. und Michael F. zeigen, dass beide die Version IAR 8.50.9 genutzt haben. Bei Michael wird aber der Wert im Watch Fenster als negativer Wert dargestellt. Eine Frage an Mach: hast Du mal wirklich ein clean und rebuild all gemacht?
Und noch eine blöde Frage: Ihr habt nicht zufällig euch den Datentyp int8_t durch ein uraltes Makro im Code ala #define int8_t .... verbastelt? Hatte zwar auch schon Probleme mit der IAR Workbench, aber meistens lag das Problem doch eher auf Programmiererseite...
Marc schrieb: > Also der Debugger ist schon grenzwertig. > Er zeigt als Datentyp int8_t und den Wert als char plus uint8_t. Wie ich oben schon schrieb, ist es bei Hex-Zahlen nicht üblich, sie mit Vorzeichen anzuzeigen, schon gar nicht im C-Umfeld. Die Hex-Schreibweise dient ja primär dazu, das Bitmuster herauslesen zu können, was aber bei negativem Vorzeichen, arg erschwert würde. Marc schrieb: > Interessant, die Screenshots von Mach F. und Michael F. zeigen, dass > beide die Version IAR 8.50.9 genutzt haben. Bei Michael wird aber der > Wert im Watch Fenster als negativer Wert dargestellt. Bei Michael wird er nicht hexadezimal, sondern dezimal und deswegen mit Vorzeichen dargestellt. Ich schätze, dass man das Ausgabeformat im Debugger irgendwo einstellen kann.
> [assembler.jpg]
Sieht vollkommen korrekt aus - macht genau das, was im C-Code steht.
Wäre natürlich hilfreich gewesen, zu wissen, welchen Wert R7 in der
grünen Zeile hat und wo jetzt überhaupt ein "Fehler" auftritt (das
ursprüngliche IF gibt's ja nicht mehr).
Yalu X. schrieb: > Die Hex-Schreibweise > dient ja primär dazu, das Bitmuster herauslesen zu können, was aber bei > negativem Vorzeichen, arg erschwert würde. Bei Anzeige von "char" ist das natürlich so, da hätte ich ggf auch eine dazu passende Hex Zahl. Aber der Debugger zeigt ja "int8_t" als Datentyp an, da hätte ich erwartet, dass er automatisch den dezimaln Wert mit Vorzeichen anzeigt.
Mach F. schrieb: > ich habe ja geschrieben dass der breakpoint nicht getriggert wird. Dazu müsstest Du den Code Posten. Es ist je nach Optimierungsstufe möglich, dass dort kein eigener Code ist. Mache ein nop hin und zeig den Code.
foobar schrieb: > Sieht vollkommen korrekt aus Sehe ich auch so. Ich schätze, dass danach in bWheelNegative auch der erwartete Wert steht. Aber der Code ist ja ein ganz anderer als der ursprüngliche, in dem der Fehler auftrat. Zum einen gibt es dort die if-Anweisung, zum anderen wird dort nWheelInc schon vor dem Aufruf von scp_transmit beschrieben. Wer weiß, ob nicht in scp_transmit auf Grund eines Pufferüberlaufs o.ä. nWheelInc überschrieben wird, so dass bei der if-Anweisung ein ganz anderer Wert ankommt. @Mach: Hast du dir eigentlich in deinem ursprünglichen Code den Breakpoint auch mal auf die if-Anweisung gesetzt und dir dort den Wert von nWheelInc anzeigen lassen? In deinen bisherigen Screenshots sieht es so aus, als ob du nur die korrekte Zuweisung in nWheelInc=... überprüft hast, nicht aber, ob der Variableninhalt danach möglicherweise geändert wurde. @Marc: Marc schrieb: > Aber der Debugger zeigt ja "int8_t" als Datentyp an, da hätte ich > erwartet, dass er automatisch den dezimaln Wert mit Vorzeichen > anzeigt. Ja, sinnvoller wäre das auf jeden Fall. Immerhin hat es Michael geschafft, dem Debugger auch die Dezimaldarstellung zu entlocken.
:
Bearbeitet durch Moderator
Mach F. schrieb: > Oliver S. schrieb: >> Kriegst du das hin? > bitte schön Schon ganz prima... Wenn’s jetzt noch der nicht funktionierende Code wäre, und dazu als Text, und nicht als Bild, wäre es noch besser... Oliver
Oliver S. schrieb: > Wenn’s jetzt noch der nicht funktionierende Code wäre, Den hat er ja noch nie gezeigt. Er hat nicht einmal gesagt, ob der Code nicht funktioniert hat oder was falsch lief. Er hatte eigentlich nur einen Breakpoint, der nicht gebreakt hat. Mach F. schrieb: > Wenn ich einen Breakpoint im else setze, wird dieser nicht getriggert, > auch bei 0xFF oder eben -1 nicht.
Oliver S. schrieb: > Wenn’s jetzt noch der nicht funktionierende Code wäre, und dazu als > Text, und nicht als Bild, wäre es noch besser...
1 | static void on_cmd_wheel_turned_f(const uint8_t *data_p, uint_fast16_t data_length) { |
2 | /*-- Local Variables ---------------------------------------------------------------*/
|
3 | union tDATA_Event_RemoteControl t_RemoteControl; |
4 | |
5 | uint8_t response_a[SCP_PAYLOAD_MAX_LENGTH]; |
6 | size_t response_len = 0; |
7 | int8_t nWheelInc = 0; |
8 | uint16_t nLogValue = 0; |
9 | |
10 | /*-- Code Statements ---------------------------------------------------------------*/
|
11 | nWheelInc = (int8_t) BUF_READ_BE_U8_F(data_p, 0); |
12 | |
13 | response_a[response_len++] = SCP_STATUS_OK; |
14 | scp_transmit_f(SCP_CMD_WITH_ACK_F(CMD_WHEEL_TURNED), response_a, response_len); |
15 | |
16 | if (nWheelInc >= 0) { |
17 | t_RemoteControl._Integer.Integer = (uint8_t) nWheelInc; |
18 | IN_ReleaseUnit.Event_RemoteControl(Event_RemoteControl_Increment, &t_RemoteControl); |
19 | } else { |
20 | //invert the Increments
|
21 | t_RemoteControl._Integer.Integer = (uint8_t) -nWheelInc; |
22 | IN_ReleaseUnit.Event_RemoteControl(Event_RemoteControl_Decrement, &t_RemoteControl); |
23 | }
|
24 | |
25 | BUF_WRITE_BE_U8_F(nLogValue, 0, CMD_WHEEL_TURNED); |
26 | BUF_WRITE_BE_U8_F(nLogValue, 1, (uint8_t) nWheelInc); |
27 | |
28 | WriteDiagnoseBuffer (SENSOR_RC_COMMAND, nLogValue); |
29 | }
|
Hab es reverted und beim Watch auf dez gestellt, rebuild all, jetzt funktioniert auch dieser erste Code. Der einzige Unterschied zum init Post war das Rebuild all... Entschuldigt bitte all die Zeit die Ihr aufgewendet habt, aber eine anregende Diskussion war es allemal. Schönen Abend allerseits
Mach F. schrieb: > Hab es reverted und beim Watch auf dez gestellt, rebuild all, jetzt > funktioniert auch dieser erste Code. Das ist hoch anständig von Dir, dass Du es am Ende doch noch mal versucht hast und das Ergebnis postest. Ich dachte schon, Du wärest mit Deinen "Patchen" zufrieden. Aus sowas entsteht schnell Voodoo: Wenn etwas nicht geht, dann obskure Verrenkungen weil "der Compiler spinnt". Das gibt es natürlich auch, aber nicht bei O0 und trivialen Dingen. Und wenn doch, sollte man erst Recht nicht flicken, bevor man den Fehler isoliert und vom Hersteller bestätigt hat. Wenn man einfachen Anweisungen nicht trauen kann, wie soll man jemals Fehler suchen.
A. S. schrieb: > Das ist hoch anständig von Dir, dass Du es am Ende doch noch mal > versucht hast und das Ergebnis postest. Ich dachte schon, Du wärest mit > Deinen "Patchen" zufrieden. Aus sowas entsteht schnell Voodoo: Wenn > etwas nicht geht, dann obskure Verrenkungen weil "der Compiler spinnt". Das ist das Mindeste was ich tun sollte nachdem alle so viel Zeit damit verbracht haben. Danke
Oliver S. schrieb: > (prx) A. K. schrieb: >> Das Verhalten müsste also bei IAR irgendwo dokumentiert sein. > > Indirekt ist es das in dem o.a. link: Jein... Das implementation defined behavior des IAR Compilers ist im "C/C++ Reference Guide" beschrieben. Yalu X. schrieb: > Bei Michael wird er nicht hexadezimal, sondern dezimal und deswegen mit > Vorzeichen dargestellt. Ich schätze, dass man das Ausgabeformat im > Debugger irgendwo einstellen kann. Der Debugger zeigt im Watch-Fenster per Default den Wert als ASCII + HEX an. Über einen rechts-klick auf die Variable kann das Ganze dann beispielsweise als "Dezimal" interpretiert werden. Über "Show As" sind dann noch mehr Optionen möglich (siehe Screenshot). Gruß, Michael
Mach F. schrieb: > Der einzige Unterschied zum init > Post war das Rebuild all... Hatte ich dir ja schon oben geschrieben, dass der IAR v8 da ein paar üble Macken hat ;) Auf einem SAM9G45 setzt der neue IAR8.x übrigens manchmal den Breakpoint nicht wenn die CPU läuft. Es hat sich nur der IAR von v7.x auf v8.3/8.5 geändert. Gleicher J-Link, gleiches HW Target, gleicher PC, kein Win10 Update zwischendurch. Da haste eine main Schleife und weist zu 100%, dass der da durchläuft. Setzt den Breakpointer, der kommt nicht. Drückst beim IAR auf Pause und dann run -> Breakpoint kommt. Ganz großes Kino! Auf STM32 ist das bisher allerdings nicht passiert. Da hat der IAR eine ganz andere Marotte! Manchmal überspringt er Funktionen bei F11 (Step Into). Passiert nur auf unseren STM32 Targets, auf dem dicken Cortex-A passierts nicht. Zudem hab ichs nur bei CPP Code mit virtual functions (Sprungtabelle) erlebt. Da verschluckt er sich wohl manchmal... Mach F. schrieb: > Entschuldigt bitte all die Zeit die Ihr aufgewendet habt Es hat ja vor allem viel Entwicklerzeit für die Firma gekostet, nämlich deine. Wenn das öfter vorkommt muss man mals Tooling überdenken ;) @Michael F: Was machen die rutschenden Breakpoints? Da gabs im THread ja kein STatusupdate mehr von dir.
Mw E. schrieb: > Es hat ja vor allem viel Entwicklerzeit für die Firma gekostet, nämlich > deine. > Wenn das öfter vorkommt muss man mals Tooling überdenken ;) korrekt, aber so ist es nun mal in der Entwicklung, wird nicht das erste und nicht das letzte Mal so sein...
Mach F. schrieb: > korrekt, aber so ist es nun mal in der Entwicklung, wird nicht das erste > und nicht das letzte Mal so sein... Na ja, das könnte dein Chef anders sehen. Der bezahlt dich für Ergebnisse, nicht zum rumprobieren. Oliver
Oliver S. schrieb: > Na ja, das könnte dein Chef anders sehen. Der bezahlt dich für > Ergebnisse, nicht zum rumprobieren. genau so ist es, nur Ergebnisse zählen, aber jeder und jede die in der Entwicklung arbeiten wissen auch, dass der Tag 24h hat und nicht immer alles nach Plan läuft, zumindest habe ich das noch nie erlebt, wäre ja auch langweilig... obwohl es zugegebenermassen ein wirklich sehr sehr dummer "Bug" war aber das gibt es nun mal... Schönen Abend noch
Mw E. schrieb: > Auf einem SAM9G45 setzt der neue IAR8.x übrigens manchmal den Breakpoint > nicht wenn die CPU läuft. > Es hat sich nur der IAR von v7.x auf v8.3/8.5 geändert. > Gleicher J-Link, gleiches HW Target, gleicher PC, kein Win10 Update > zwischendurch. Mw E. schrieb: > Manchmal überspringt er Funktionen bei F11 (Step Into). > Passiert nur auf unseren STM32 Targets, auf dem dicken Cortex-A > passierts nicht. > Zudem hab ichs nur bei CPP Code mit virtual functions (Sprungtabelle) > erlebt. Gehe ich recht in der Annahme, dass Du zu beiden Themen Support-Requests gestartet hast, damit die Probleme genauer untersucht werden können? Mach F. schrieb: > obwohl es zugegebenermassen ein wirklich sehr sehr > dummer "Bug" war aber das gibt es nun mal... Es wäre gut gewesen, gleich von Anfang an den erzeugten Assembler-Code zu posten, da nun nicht mehr nachvollziehbar ist, was schief gelaufen sein könnte... Gruß, Michael
Michael F. schrieb: > Es wäre gut gewesen, gleich von Anfang an den erzeugten Assembler-Code > zu posten, da nun nicht mehr nachvollziehbar ist, was schief gelaufen > sein könnte... Klar, soll auch keine Kritik sein sondern eher auf mich selbst bezogen, rebuild all hätte mir auch selbst einfallen können. Danke
Beitrag #6649245 wurde von einem Moderator gelöscht.
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
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.