Dies ist auf undefiniertes Verhalten zurückzuführen. Sie greifen mc
bei der letzten Iteration Ihrer Schleife außerhalb der Grenzen auf das Array zu . Einige Compiler führen möglicherweise eine aggressive Schleifenoptimierung unter der Annahme durch, dass kein undefiniertes Verhalten vorliegt. Die Logik wäre wie folgt:
- Der Zugriff
mc
außerhalb der Grenzen ist ein undefiniertes Verhalten
- Nehmen Sie kein undefiniertes Verhalten an
- Daher
di < 4
ist immer wahr, da sonst mc[di]
undefiniertes Verhalten aufrufen würde
gcc mit aktivierter Optimierung und Verwendung des -fno-aggressive-loop-optimizations
Flags verschwindet das Verhalten der Endlosschleife ( siehe live ). Während ein Live-Beispiel mit Optimierung, aber ohne -fno-aggressive-Schleifenoptimierungen, das von Ihnen beobachtete Endlosschleifenverhalten zeigt.
Ein Godbolt-Live-Beispiel des Codes zeigt, dass die di < 4
Prüfung entfernt und durch ein bedingungsloses jmp ersetzt wurde:
jmp .L6
Dies ist fast identisch mit dem in GCC vor 4.8 Breaks Broken SPEC 2006 Benchmarks beschriebenen Fall . Die Kommentare zu diesem Artikel sind ausgezeichnet und es lohnt sich zu lesen. Es wird darauf hingewiesen, dass Clang den Fall in dem Artikel -fsanitize=undefined
erfasst hat, mit dem ich ihn für diesen Fall nicht reproduzieren kann, aber mit gcc -fsanitize=undefined
( siehe live ). Der wahrscheinlich berüchtigtste Fehler bei einem Optimierer, der auf undefiniertes Verhalten schließen lässt, ist das Entfernen der Nullzeigerprüfung des Linux-Kernels .
Obwohl dies eine aggressive Optimierung ist, ist es wichtig zu beachten, dass, wie der C ++ - Standard sagt, undefiniertes Verhalten ist:
Verhalten, für das diese Internationale Norm keine Anforderungen stellt
Was im Wesentlichen bedeutet, dass alles möglich ist und es bemerkt ( Hervorhebung von mir ):
[...] Zulässiges undefiniertes Verhalten reicht vom vollständigen Ignorieren der Situation mit unvorhersehbaren Ergebnissen über das Verhalten während der Übersetzung oder Programmausführung in einer dokumentierten, für die Umgebung charakteristischen Weise (mit oder ohne Ausgabe einer Diagnosemeldung) bis zum Beenden einer Übersetzung oder Ausführung (mit der Ausgabe einer Diagnosemeldung). [...]
Um eine Warnung von gcc zu erhalten, müssen wir die cout
Außenseite der Schleife verschieben und dann sehen wir die folgende Warnung ( sehen Sie sie live ):
warning: iteration 3u invokes undefined behavior [-Waggressive-loop-optimizations]
for(di=0; di<4;di++,delta=mc[di]){ }
^
Dies hätte wahrscheinlich ausgereicht, um das OP mit genügend Informationen zu versorgen, um herauszufinden, was vor sich ging. Solche Inkonsistenzen sind typisch für die Verhaltensweisen, die wir bei undefiniertem Verhalten beobachten können. Um ein besseres Verständnis dafür zu erhalten, warum solche Warnungen angesichts undefinierten Verhaltens inkonsistent sein können, warum können Sie bei der Optimierung aufgrund undefinierten Verhaltens nicht warnen? ist eine gute Lektüre.
Hinweis, -fno-aggressive-loop-optimizations
ist in den Versionshinweisen zu gcc 4.8 dokumentiert .