Ich schreibe in C mit dem Atmel Studio (AVR-C.)
Ich habe eine if-Anweisung:
if( (rxProcessing < (rxWritePos-1) ) )
Wo rxProcessing
und rxWritePos
sind bereits Typ uint8_t
. und ich möchte, dass das Ergebnis von (rxWritePos-1)
ein 8-Bit-Int ohne Vorzeichen ist (so dass zum Beispiel, wenn rxWritePos 0 ist, 0-1 = 255 ist.)
Ich möchte sicher sein, dass das Ergebnis der Subtraktion dort immer ein 8-Bit-Wert ohne Vorzeichen ist. Wie kann ich das Ergebnis konvertieren (oder sicherstellen, dass) (rxWritePos-1)
immer ein vorzeichenloses 8-Bit-Int sein?
Ich denke, das wird reichen:
if( (rxProcessing < ((uint8_t)rxWritePos-1) ) )
Beachten Sie, dass , und ich weiß, dass ich eine Variable wie folgt in uint8_t umwandeln/umwandeln kann: uint8_t y = (uint8_t) x;
aber ich möchte sicherstellen, dass die Umwandlung innerhalb von if() stattfindet.
Sie benötigen Klammern um den gesamten Ausdruck: (uint8_t)(rxWritePos-1)
.
Wenn rxWritePos
= 0:
rxWritePos - 1
= −1rxWritePos - 1u
= eine große Zahl (unsignierter Wrap-Around mit dem Typ von 1u
)(uint8_t)(rxWritePos-1)
= (uint8_t)(-1)
= 255.Dies wird alles durch die Type-Promotion-Regeln von C geregelt, die etwas unintuitiv sein können. Seien Sie besser offensichtlich.
Wenn Sie nun sagen, dass die Konvertierung innerhalb der if-Anweisung erfolgen soll, ist dies eine gültige Frage, um die richtige Syntax zu finden. Dies wird jedoch höchstwahrscheinlich zu genau demselben Maschinencode kompiliert wie das Deklarieren einer neuen Variablen direkt vor der if-Anweisung, was klarer sein kann (bezüglich: besser offensichtlich sein).
rxWritePos
ist schon uint8_t
so offensichtlich das die besetzung (uint8_t)rxWritePos
unsinnig ist - du begibst es auf den typ den es schon hat. Ebenso ist es riskant, "viele Berechnungen durchzuführen und dann in den beabsichtigten Typ umzuwandeln". Die Berechnung selbst könnte unbeabsichtigte Dinge enthalten.
Hier geht es hauptsächlich um implizite Type Promotion . int
Operanden von binären Operatoren werden normalerweise zu , einem vorzeichenbehafteten Typ, heraufgestuft . Wir wollen fast nie signierte Typen in eingebetteten Systemen haben, das ist also problematisch.
1
Darüber hinaus ist die Integer-Konstante auch vom Typ int
, der vorzeichenbehaftet ist. Wie es der Zufall will, hätte es viele Probleme gelöst, es so zu schreiben 1u
und durchzusetzen, wie es ist .unsigned int
Abgesehen von der Signierbarkeit wollen wir auf allen alten 8-Bit-MCUs 16-Bit-Arithmetik möglichst vermeiden. Wenn es also aufgrund impliziter Heraufstufung zu versehentlichen Vorzeichenänderungen kommt, können diese auch die Optimierung blockieren und den Compiler zwingen, die Berechnung in 16 Bit durchzuführen. Weil es nicht wissen kann, ob Sie den Code geschrieben haben und auf die implizite Beförderung zählen oder nicht.
Die richtige/robusteste Lösung für Ihr Problem ist jedoch wahrscheinlich, die Berechnung in mehreren Schritten mit einer temporären Variablen durchzuführen.
uint8_t writePos = rxWritePos;
writePos--;
if(rxProcessing < writePos)
Hier writePos--
wird garantiert nicht befördert und es wird vorzeichenlose 8-Bit-Arithmetik verwendet. Ganzzahlen ohne Vorzeichen können nicht über-/unterlaufen, sondern haben stattdessen einen wohldefinierten Umlauf von 255 bis 0, was Sie möchten.
(uint8_t)((rxWritePos-1) & 255)
Bei jeder Berechnung müssen Sie eine Maske anlegen, dann erhalten Sie immer das richtige Ergebnis.
U
dort nicht immer noch das Präfix verwenden? Wie:255U
Hasan Alattar
Jason S
Christianidis Vasileios
Lundin