Це пов’язано з невизначеною поведінкою, ви отримуєте доступ до масиву mc
поза межами останньої ітерації вашого циклу. Деякі компілятори можуть виконувати агресивну оптимізацію циклу навколо припущень про відсутність невизначеної поведінки. Логіка буде схожа на таку:
- Доступ
mc
поза межами - невизначена поведінка
- Не приймайте жодної невизначеної поведінки
- Отже,
di < 4
це завжди правда, оскільки в іншому випадку mc[di]
викличе невизначену поведінку
gcc з увімкненою оптимізацією та використанням -fno-aggressive-loop-optimizations
прапора змушує поведінку нескінченного циклу зникати ( дивіться це в прямому ефірі ). Хоча живий приклад з оптимізацією, але без -fno-агресивної-циклічної оптимізації демонструє нескінченну поведінку циклу, яку ви спостерігаєте.
Godbolt живий приклад коду показує di < 4
чек видаляється і замінюється і безумовна JMP:
jmp .L6
Це майже ідентично випадку, викладеному в Порівняльних стандартах GEC до 4.8 . Коментарі до цієї статті чудові і їх варто прочитати. Він зазначає, що Clang зафіксував цей випадок у статті, використовуючи -fsanitize=undefined
яку я не можу відтворити для цієї справи, але gcc використовуючи -fsanitize=undefined
робить ( дивіться в прямому ефірі ). Ймовірно, найбільш ганебною помилкою навколо оптимізатора, який робить висновок щодо невизначеної поведінки, є видалення перевірки нульового вказівника ядра Linux .
Хоча це агресивна оптимізація, важливо зазначити, що як зазначає стандарт C ++, невизначена поведінка:
поведінка, щодо якої цей міжнародний стандарт не вимагає жодних вимог
Що по суті означає, що все можливо, і це зазначає ( наголос на моєму ):
[...] Допустима невизначена поведінка варіюється від ігнорування ситуації повністю з непередбачуваними результатами , до поведінки під час перекладу або виконання програми документованим чином, характерним для середовища (з видачею діагностичного повідомлення або без нього), до припинення перекладу або виконання (з видачею діагностичного повідомлення). [...]
Для того, щоб отримати попередження від gcc, нам потрібно перемістити cout
зовнішню частину циклу, після чого ми побачимо таке попередження ( перегляньте його в прямому ефірі ):
warning: iteration 3u invokes undefined behavior [-Waggressive-loop-optimizations]
for(di=0; di<4;di++,delta=mc[di]){ }
^
що, ймовірно, було б достатнім для надання ОП достатньої інформації для з'ясування того, що відбувається. Така невідповідність є типовою для тих типів поведінки, які ми можемо побачити при невизначеній поведінці. Щоб краще зрозуміти, чому таке попередження може бути непомітним перед невизначеною поведінкою Чому ви не можете попередити при оптимізації на основі невизначеної поведінки? добре читати.
Примітка, -fno-aggressive-loop-optimizations
це задокументовано у примітках до випуску gcc 4.8 .