Контекст
Меня спросила следующая головоломка одного из моих друзей:
void fn(void)
{
/* write something after this comment so that the program output is 10 */
/* write something before this comment */
}
int main()
{
int i = 5;
fn();
printf("%d\n", i);
return 0;
}
Я знаю, что может быть несколько решений, некоторые из которых связаны с макросом, а некоторые - что-то о реализации и нарушении C.
Единственное конкретное решение, которое меня интересовало, - это сделать некоторые предположения о стеке и написать следующий код: (Я понимаю, что это поведение undefined, но может работать как ожидается во многих реализациях)
void fn(void)
{
/* write something after this comment so that the program output is 10 */
int a[1] = {0};
int j = 0;
while(a[j] != 5) ++j; /* Search stack until you find 5 */
a[j] = 10; /* Overwrite it with 10 */
/* write something before this comment */
}
Проблема
Эта программа отлично работала в MSVC и gcc без оптимизации. Но когда я скомпилировал его с флагом gcc -O2
или попытался на ideone, он бесконечно петлит в функции fn
.
Мое наблюдение
Когда я скомпилировал файл с gcc -S
vs gcc -S -O2
и сравнил, он ясно показывает, что gcc
хранит бесконечный цикл в функции fn
.
Вопрос
Я понимаю, потому что код вызывает поведение undefined, его нельзя назвать ошибкой. Но почему и как компилятор анализирует поведение и оставляет бесконечный цикл в O2
?
Многие люди прокомментировали это поведение, если некоторые переменные изменены на изменчивые. Ожидаемый результат:
- Если
i
илиj
изменено наvolatile
, поведение программы остается таким же. - Если массив
a
сделанvolatile
, программа не терпит бесконечного цикла. - Кроме того, если я применил следующий патч
- int a[1] = {0};
+ int aa[1] = {0};
+ int *a = aa;
Поведение программы остается таким же (бесконечный цикл)
Если я скомпилирую код с помощью gcc -O2 -fdump-tree-optimized
, я получаю следующий промежуточный файл:
;; Function fn (fn) (executed once)
Removing basic block 3
fn ()
{
<bb 2>:
<bb 3>:
goto <bb 3>;
}
;; Function main (main) (executed once)
main ()
{
<bb 2>:
fn ();
}
Invalid sum of incoming frequencies 0, should be 10000
Это проверяет утверждения, сделанные после ответов ниже.