Код: Выделить всё
int foo(int *a, long *b)
{
int t = *a;
*b = 0; // cannot change *a
return *a - t; // can be folded to zero
}
Поскольку a и b объявлены указателями к несовместимым типам, а поскольку C и C++ требуют, чтобы объекты имели доступ к сохраненному значению только с помощью lvalue совместимого типа, сохранение в *b не может повлиять на значение *a, кэшированное в переменной. t, который обычно является регистром. Следовательно, операнды в выражении вычитания должны быть равны, а результат должен быть нулевым.
Но во второй части мы видим аналогичный пример:< /p>
Код: Выделить всё
int bar(int *a, long *b)
{
int t = *a;
for (int i = 0; i != sizeof *b; ++i)
((unsigned char*)b)[i] = 0;
return *a - t; // must not be folded
}
В этом случае компилятор не может свернуть возвращаемое выражение потому что функция будет действительна, если она будет вызвана с b, равным a. Однако использование ограничения при объявлении указателей a и b сделает вызов f с перекрывающимися объектами недействительным. Это снова предоставит возможность оптимизации.
Я понимаю, что беззнаковый символ * можно использовать для псевдонимов так же, как и char * может. Но насколько я понимаю, a и b уже сигнализируют, что они не будут использовать псевдонимы в обеих сигнатурах, поскольку одна из них — int *, а другая — длинная * .
Моя мысленная модель заключается в том, что типы аргументов функции подчиняются строгим правилам псевдонимов, поэтому в любом случае...
- и b занимают перекрывающуюся память (например, через reinterpret_cast), и мы находимся на территории UB
Код: Выделить всё
a
- и b имеют непересекающиеся представления в памяти
Код: Выделить всё
a
Почему использование каламбура внутри bar изменить, может ли компилятор свернуть выражение *a - t?
Подробнее здесь: https://stackoverflow.com/questions/791 ... imizations