Как правило, компилятору разрешено делать что угодно , если результат такой же, как если бы он скомпилировал ваш код в точности так, как написано.
Фактически, ваш типичный компилятор C / C ++, с любыми разумными флагами оптимизации, имеет такую функцию, как:
void f (void) {
int a = 20;
int b = 10;
}
просто скомпилирует это как:
f:
ret
Другими словами, он будет обрабатывать его как пустую функцию. Причина в том, что функция не имеет никаких эффектов; этим переменным присваиваются значения, но их значения никогда не используются (в технических терминах они мертвые хранилища ), и поэтому компилятор может их игнорировать.
Теперь давайте посмотрим на более практичный пример:
void foo (int num, int * num2, int * num3) {
*num2 = num * 2;
*num3 = num * 3;
}
Может ли компилятор переупорядочить эти операторы? Ответ фирмы нет . Причина в том, что num2
и num3
могут указывать на один и тот же адрес (другими словами, вы можете вызывать функцию, например foo(3, &bar, &bar)
), и, следовательно, порядок записи имеет значение. С другой стороны, только в C (но не в C ++) мы могли бы написать это так:
void foo (int num, int * restrict num2, int * restrict num3) {
*num2 = num * 2;
*num3 = num * 3;
}
В этом случае ключевое слово restrict
сообщает компилятору, что указатели должны указывать на разные адреса, и, следовательно, изменение порядка операторов допустимо, поскольку результаты одинаковы независимо от порядка их выполнения.