Überschriebenen Überlauf in C / C ++ erkennen

Auf den ersten Blick, diese Frage mag wie eine Kopie der Wie zu erkennen integer-überlauf?aber es ist tatsächlich deutlich anders.

Habe ich gefunden, dass während der Erkennung eine vorzeichenlose integer-überlauf ist ziemlich trivial, das erkennen einer unterzeichnet überlauf in C/C++ ist eigentlich schwieriger, als die meisten Leute denken.

Den meisten offensichtlich, doch naiv, so zu tun, es wäre so etwas wie:

int add(int lhs, int rhs)
{
 int sum = lhs + rhs;
 if ((lhs >= 0 && sum < rhs) || (lhs < 0 && sum > rhs)) {
  /* an overflow has occurred */
  abort();
 }
 return sum; 
}

Das problem mit diesem ist, dass nach dem C-standard, Ganzzahl-überlauf ist Undefiniertes Verhalten. In anderen Worten, gemäß der Norm, sobald Sie selbst die Ursache unterzeichnet überlauf, Ihr Programm ist genauso hinfällig, wie wenn Sie dereferenziert einen null-Zeiger. Man kann also nicht die Ursache zu undefiniertem Verhalten, und versuchen Sie dann zu erkennen, den überlauf nach der Tat, wie in der oben genannten post-condition check Beispiel.

Obwohl die obige Prüfung ist wahrscheinlich zu arbeiten auf viele Compiler können Sie nicht rechnen. In der Tat, da der C-standard sagt signed integer overflow nicht definiert ist, sind einige Compiler (z.B. GCC) wird optimieren Sie Weg, die obige Prüfung wenn Optimierungs-flags gesetzt sind, da der compiler davon eine signiert überlauf ist unmöglich. Diese völlig unterbricht den Versuch, zu prüfen, für überlauf.

So, eine andere Möglichkeit zu prüfen, für überlauf wäre:

int add(int lhs, int rhs)
{
 if (lhs >= 0 && rhs >= 0) {
  if (INT_MAX - lhs <= rhs) {
   /* overflow has occurred */
   abort();
  }
 }
 else if (lhs < 0 && rhs < 0) {
  if (lhs <= INT_MIN - rhs) {
   /* overflow has occurred */
   abort();
  }
 }

 return lhs + rhs;
}

Dieser scheint vielversprechend, da wir eigentlich nicht hinzuzufügen, die zwei Ganzzahlen miteinander, bis wir stellen Sie im Voraus sicher, dass die Durchführung solch einer Beurteilung führt nicht zum überlaufen. Also, wir führen nicht irgendwelche undefinierten Verhalten.

Jedoch, diese Lösung ist leider sehr viel weniger effizient als die erste Lösung, da Sie zum durchführen einer subtract-operation, nur um zu testen, ob die addition funktioniert. Und selbst wenn Sie don ' T care über diese (kleinen) Leistungseinbruch, ich bin noch nicht ganz überzeugt, dass diese Lösung ausreichend ist. Der Ausdruck lhs <= INT_MIN - rhs scheint, genau wie die Art von Ausdruck, der compiler kann optimieren entfernt werden, zu denken, dass signed-überlauf ist unmöglich.

So gibt es eine bessere Lösung? Etwas, das garantiert wird, um 1) führen nicht zu undefiniertem Verhalten, und 2) nicht die compiler die Möglichkeit zur Optimierung entfernt überlauf überprüft? Ich dachte vielleicht gibt es einen Weg, es zu tun, indem man beide Operanden in unsigned und die Durchführung von Kontrollen durch Ihre eigenen Rollen zweier-Komplement-Arithmetik, aber ich bin mir nicht wirklich sicher, wie das zu tun.

InformationsquelleAutor der Frage Channel72 | 2010-10-15

Schreibe einen Kommentar