Dies ist auf undefiniertes Verhalten zurückzuführen. Sie greifen mcbei 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
mcaußerhalb der Grenzen ist ein undefiniertes Verhalten
- Nehmen Sie kein undefiniertes Verhalten an
- Daher
di < 4ist immer wahr, da sonst mc[di]undefiniertes Verhalten aufrufen würde
gcc mit aktivierter Optimierung und Verwendung des -fno-aggressive-loop-optimizationsFlags 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 < 4Prü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=undefinederfasst 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 coutAuß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-optimizationsist in den Versionshinweisen zu gcc 4.8 dokumentiert .