Це пов’язано з невизначеною поведінкою, ви отримуєте доступ до масиву 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 .