Почему компилятор может оптимизировать сравнение при доступе за границы массива?
bool contains(int val) {
int arr[] = {1, 2, 3};
for (int i = 0; i <= 3; ++i)
if (arr[i] == val)
return true;
return false;
}
#include <iostream>
int main() {
std::cout << contains(2);
std::cout << contains(4);
}
Почему с оптимизацией -O2 компилятор может превратить функцию в возврат единицы?
Понятно, что тут неопределённое поведение, но непонятно, почему оно позволяет так оптимизировать код, что результат в итоге неверный.
Ответы (1 шт):
Преобразование допустимо, потому что стандарт не определяет поведение программы в этом случае, а значит может быть всё что угодно.
По какой логике компилятор мог преобразовать вызов функции в return true;?
Потому что исполнение return false; может произойти, только если arr[3] == val стало false, но с точки зрения компилятора программист предоставляет гарантию об отсутствии неопределённого поведения, а значит доступа arr[3] не может произойти. Раз не может произойти доступа arr[3], то и arr[3] == val не может стать false. Так как все оставшиеся пути выполнения функции возвращают true, можно соптимизировать её до чистого return true;.
Кстати, gcc в этом смысле более агрессивен; clang возвращает значение, в зависимости от того, меньше ли переданный аргумент минус единица тройки, получая ожидаемый результат (сравнение). С -O1 результаты верные у обоих компиляторов.
Использовались комментарии участников @user7860670, @Chorkov, @gauss.