c++ - Compileroptimierung von bitweiser Nichtbedienung




embedded iar (2)

Ich habe eine einfache Funktionsprüfung, ob zwei Arrays jeweils invers sind. Sie scheinen bis auf eine tmp Variable identisch zu sein. Einer arbeitet, der andere nicht. Ich kann nicht für das Leben von mir herausfinden, warum der Compiler dies optimieren würde - wenn es tatsächlich ein Optimierungsproblem ist (mein Compiler ist IAR Workbench v4.30.1). Hier ist mein Code:

// this works as expected
uint8 verifyInverseBuffer(uint8 *buf, uint8 *bufi, uint32 len)
{
  uint8 tmp;
  for (uint32 i = 0; i < len; i++)
  {
    tmp = ~bufi[i];
    if (buf[i] != tmp)
    {
      return 0;
    }
  }
  return 1;  
}

// this does NOT work as expected (I only removed the tmp!)
uint8 verifyInverseBuffer(uint8 *buf, uint8 *bufi, uint32 len)
{
  for (uint32 i = 0; i < len; i++)
  {
    if (buf[i] != (~bufi[i]))
    {
      return 0;
    }
  }
  return 1;  
}

Die erste Version des Codes funktioniert, die zweite nicht. Kann jemand herausfinden, warum? Oder kommen Sie mit einigen Tests, um herauszufinden, was nicht stimmt?


Das Problem ist die ganzzahlige Heraufstufung. Der Operator ~ ist sehr gefährlich!

Im Fall von ~bufi[i] wird der Operand von ~ gemäß den ganzzahligen Beförderungen befördert. Den Code äquivalent zu ~(int)bufi[i] .

Also im zweiten Fall buf[i] != (~bufi[i]) bekommst du so etwas wie 0xXX != 0xFFFFFFFFYY , wobei "XX" und "YY" die tatsächlichen Werte sind, die du vergleichen willst und 0xFFFF dort ein unbeabsichtigter Mist ist indem Sie das bitweise Komplement eines int . Dies wird immer als true ausgewertet, damit der Compiler Teile des Codes optimieren und einen sehr subtilen Fehler erzeugen kann.

Im Falle von tmp = ~bufi[i]; Sie können diesem Fehler ausweichen, indem Sie 0xFFFFFFFFYY in "YY", den Wert, an dem Sie interessiert sind, 0xFFFFFFFFYY .

Weitere Informationen finden Sie unter Regeln für die implizite Typheraufstufung. Erwägen Sie auch, MISRA-C zu verwenden, um solchen subtilen Fehlern auszuweichen.


Was Sie sehen, ist ein Ergebnis der Regeln für ganzzahlige Werbeaktionen . Immer wenn eine Variable kleiner als ein int in einem Ausdruck verwendet wird, wird der Wert auf den Typ int .

Angenommen, bufi[i] enthält den Wert 255. Die 0xFF Darstellung davon ist 0xFF . Dieser Wert ist dann der Operand des Operators ~ . Daher wird der Wert zuerst auf int 0x000000FF , das (vorausgesetzt, es handelt sich um 32-Bit) den Wert 0x000000FF hat. 0xFFFFFF00 Sie ~ auf diesen Wert 0x000000FF , erhalten Sie 0xFFFFFF00 . Sie vergleichen diesen Wert dann mit buf[i] vom Typ uint8_t . Der Wert 0xFFFFFF00 liegt außerhalb dieses Bereichs, sodass der Vergleich immer falsch ist.

Wenn Sie das Ergebnis von ~ back einer Variablen vom Typ uint8_t , wird der Wert 0xFFFFFF00 in 0x00 konvertiert. Dieser umgerechnete Wert wird dann mit buf[i] verglichen.

Das Verhalten, das Sie sehen, ist also nicht das Ergebnis einer Optimierung, sondern die Regeln der Sprache. Die Verwendung einer temporären Variablen ist eine Möglichkeit, dieses Problem zu beheben. Sie können das Ergebnis auch auf uint8 :

if(buf[i] != (uint8)(~bufi[i]))

Oder maskieren Sie alle bis auf das niedrigste Byte:

if(buf[i] != (~bufi[i] & 0xff))




iar