Falle für Unachtsame: Warum unsigned int eine Zeitbombe ist?
\n\nJeder C++-Entwickler stößt früher oder später auf eine Situation, in der Zahlen sich wie böse Kaninchen verhalten – sie springen endlos von Plus nach Null. Die Rede ist vom Überlauf von unsigned int. Im Gegensatz zu seinem vorzeichenbehafteten Gegenstück (signed int) ist der Überlauf von unsigned in C++ durch den Standard streng definiert – es ist kein UB (undefiniertes Verhalten). Die Zahl wird einfach modulo 2N gewickelt. Aber das macht den Fehler nicht weniger fatal.
Stellen Sie sich vor: Sie berechnen den Kontostand, die Anzahl der Elemente in einem Array oder die Laufzeit eines Timers. Ein zufälliger Überlauf – und die Anwendungslogik bricht zusammen. Die Frage aus dem Titel "How do I detect unsigned integer overflow?" hat auf Stack Overflow nicht umsonst tausende Aufrufe gesammelt. Lassen Sie uns drei Ansätze zur Erkennung von Überläufen analysieren: vom naiven (aber funktionierenden) bis zum professionellen.
\n\nWarum funktionieren Standardprüfungen nicht?
\n\nDas Erste, was einem Anfänger einfällt:
\n\nunsigned int a = UINT_MAX;\nunsigned int b = 1;\nif (a + b < a) // Naive Prüfung\n std::cout << "Überlauf!";\n\nDieser Code funktioniert, aber nur für Addition. Für Multiplikation, Subtraktion oder gemischte Typen bricht die Logik zusammen. Außerdem kann der Compiler eine solche Prüfung als überflüssig erachten und sie bei der Optimierung entfernen. Besonders wenn die Typen vorzeichenbehaftet sind. Verlassen Sie sich nicht auf Magie – schreiben Sie explizit.
\n\nAnsatz Nr. 1: Arithmetik vor der Operation (Pre-check)
\n\nDer zuverlässigste Weg ist, die Möglichkeit eines Überlaufs vor der Ausführung der Operation zu prüfen. Für die Addition zweier vorzeichenloser Zahlen ist die Bedingung einfach:
\n\nWenn a + b überlaufen kann, dann gilt a > (UINT_MAX - b).
#include <climits>\n#include <iostream>\n\nbool will_add_overflow(unsigned int a, unsigned int b) {\n return a > UINT_MAX - b;\n}\n\nint main() {\n unsigned int x = 4000000000;\n unsigned int y = 500000000;\n \n if (will_add_overflow(x, y)) {\n std::cerr << "Fehler: Überlauf bei Addition!\\n";\n } else {\n std::cout << "Ergebnis: " << x + y << "\\n";\n }\n return 0;\n}\n\nMultiplikation – schwieriger
\nFür die Multiplikation ist die Prüfung etwas kniffliger: a > UINT_MAX / b (und vergessen Sie nicht die Division durch Null).
bool will_mult_overflow(unsigned int a, unsigned int b) {\n if (b == 0) return false; // Multiplikation mit Null – sicher\n return a > UINT_MAX / b;\n}\n\nVorteile: Plattformunabhängigkeit, vollständige Kontrolle, keine versteckten Abhängigkeiten.
\nNachteile: Für jede Operation müssen separate Funktionen geschrieben werden. Der Code wird umfangreich.
Ansatz Nr. 2: Prüfung nach der Operation (Post-check)
\n\nDer C++-Standard garantiert, dass für unsigned-Typen das Ergebnis einer Operation (a + b) mod 2^N ist. Daher können wir die Operation ausführen und dann prüfen, ob der Wert "übergewickelt" wurde.
#include <iostream>\n#include <limits>\n\ntemplate<typename T>\nbool add_overflow(T a, T b, T& result) {\n result = a + b;\n return result < a; // Der entscheidende Trick\n}\n\nint main() {\n unsigned int res;\n if (add_overflow(4000000000u, 500000000u, res)) {\n std::cout << "Überlauf festgestellt!\\n";\n } else {\n std::cout << "OK: " << res << "\\n";\n }\n return 0;\n}\n\nWichtig: Dieser Trick funktioniert nur, wenn a und b vom gleichen vorzeichenlosen Typ sind. Für uint32_t – hervorragend. Für eine Mischung aus unsigned int und int – Fehlschlag.
Falle für Subtraktion
\nFür die Subtraktion ist die Bedingung umgekehrt: result > a.
template<typename T>\