Удаление лишних обращений к памяти
Компиляторы стремятся размещать переменные в регистрах, избегая "дорогостоящих" операций обращения к памяти. Взять хотя бы такой код: "i=*p+c; b = *p - d;". Очевидно, что второе обращение к *p лишнее и компиляторы поступают так: t =*p; i = t+c; b = t-d, при этом неявно полагается, что содержимое ячейки *p не изменяется никаким внешним кодом, в противном случае оптимизация будет носить диверсионно-разрушительный характер. Что если переменная используется для обмена данными/синхронизации нескольких потоков? Что если какой-то драйвер возвращает через нее результат своей работы? Наконец, что если мы хотим получить исключение по обращению к странице памяти? Для усмирения оптимизатора во всех этих случаях необходимо объявлять переменную как volatile
(буквально: "изменчивый", "неуловимый"), тогда при каждом обращении она будет перечитываться из памяти.
Указатели – настоящий бич оптимизации. Компилятор никогда не может быть уверен, адресуют ли две переменных различные области памяти или обращаются к одной и той же ячейке памяти.
Вот, например:
f(int *a, int *b)
{
int x;
x = *a + *b; // сложение содержимого двух ячеек
*b = 0x69; // изменение ячейки *b, адрес которой не известен компилятору
x += *a; // нет гарантии что запись в ячейку *b
не изменила ячейку *a
}