Чи можна мати цикл, який має нульовий час виконання? Я думаю, що навіть порожній цикл повинен мати час виконання, оскільки з ним пов'язані накладні витрати.
Чи можна мати цикл, який має нульовий час виконання? Я думаю, що навіть порожній цикл повинен мати час виконання, оскільки з ним пов'язані накладні витрати.
Відповіді:
Так, за правилом немов компілятор зобов'язаний лише імітувати спостережувану поведінку коду, тому якщо у вас є цикл, який не має спостережуваної поведінки, його можна повністю оптимізувати і, отже, фактично матиме нульовий час виконання .
Приклади
Наприклад, такий код:
int main()
{
int j = 0 ;
for( int i = 0; i < 10000; ++i )
{
++j ;
}
}
компілюється з gcc 4.9
використанням -O3
прапора, в основному закінчується зведенням до наступного ( дивіться в прямому ефірі ):
main:
xorl %eax, %eax #
ret
Практично всі дозволені оптимізації підпадають під правило нібито , єдиним винятком, про який я знаю, є copy elison, якому дозволено впливати на спостережувану поведінку.
Деякі інші приклади включають усунення мертвого коду, яке може видалити код, який компілятор може довести, що ніколи не буде виконаний. Наприклад, навіть незважаючи на те, що наступний цикл дійсно містить побічний ефект, його можна оптимізувати, оскільки ми можемо довести, що він ніколи не буде виконаний ( див. Його в прямому ефірі ):
#include <stdio.h>
int main()
{
int j = 0 ;
if( false ) // The loop will never execute
{
for( int i = 0; i < 10000; ++i )
{
printf( "%d\n", j ) ;
++j ;
}
}
}
Цикл буде оптимізувати так само, як і попередній приклад. Більш цікавим прикладом може бути випадок, коли обчислення в циклі можна вивести у константу, тим самим уникаючи необхідності в циклі ( не впевнений, до якої категорії оптимізації це потрапляє ), наприклад:
int j = 0 ;
for( int i = 0; i < 10000; ++i )
{
++j ;
}
printf( "%d\n", j ) ;
можна оптимізувати ( переглянути його в прямому ефірі ):
movl $10000, %esi #,
movl $.LC0, %edi #,
xorl %eax, %eax #
call printf #
Ми бачимо, що тут не задіяно жодної петлі.
Де як би Правило охоплюється стандартом
Як якби правило розглядається в проекті C99 стандарту розділі 5.1.2.3
Виконання програми , в якій мовиться:
В абстрактній машині всі вирази обчислюються відповідно до семантики. Фактична реалізація не повинна оцінювати частину виразу, якщо вона може зробити висновок про те, що його значення не використовується і що ніяких необхідних побічних ефектів не виробляється (включаючи будь-які, викликані викликом функції або доступом до нестабільного об'єкта).
Як якби правило також можна застосувати до C ++, gcc
буде виробляти один і той же результат в режимі C ++ , а також. Проект стандарту C ++ охоплює це в розділі 1.9
Виконання програми :
Семантичні описи в цьому міжнародному стандарті визначають параметризовану недетерміновану абстрактну машину. Цей міжнародний стандарт не встановлює вимог щодо структури відповідних реалізацій. Зокрема, їм не потрібно копіювати або наслідувати структуру абстрактної машини. Навпаки, відповідні реалізації потрібні для імітації (лише) спостережуваної поведінки абстрактної машини, як пояснено нижче.
Так - якщо компілятор визначить, що цикл є мертвим кодом (ніколи не буде виконуватися), він не буде генерувати код для нього. Цей цикл матиме 0 часу виконання, хоча, строго кажучи, він не існує на рівні машинного коду.
Окрім оптимізації компілятора, деякі архітектури центрального процесора, зокрема DSP, мають нульовий цикл накладних витрат , завдяки чому цикл із фіксованою кількістю ітерацій ефективно оптимізується апаратним забезпеченням, див., Наприклад, http://www.dsprelated.com/showmessage/20681 /1.php
Компілятор не зобов'язаний оцінювати вираз або частину виразу, що не має побічних ефектів і результат якого відкидається.
Harbison and Steele, C: Довідковий посібник