Оценка короткого замыкания и побочные эффекты
Хорошо, я немного смущен, чтобы задать этот вопрос, но я просто хочу быть уверенным...
Известно, что C использует оценку короткого замыкания в булевых выражениях:
int c = 0;
if (c && func(c)) { /* whatever... */ }
В этом примере func(c)
не вызывается, потому что c
имеет значение 0
. Но как насчет более сложного примера, когда побочные эффекты сравнения изменили бы следующую переменную? Вот так:
int c; /* this is not even initialized... */
if (canInitWithSomeValue(&c) && c == SOMETHING) { /*...*/ }
Функция canInitWithSomeValue
возвращает значение true и изменяет значение при заданном указателе в случае успеха. Гарантировано ли, что последующие сравнения (c == SOMETHING
в этом примере) используют значение, заданное canInitWithSomeValue(&c)
?
Независимо от того, насколько сложны оптимизаторы, используемые компилятором?
Ответы
Ответ 1
Гарантировано ли, что последующие сравнения (c == SOMETHING в этом примере) используют значение, установленное canInitWithSomeValue (& c)?
Да. Потому что есть точка последовательность
Между оценкой левого и правого операндов &&
(логическое И), ||
(логическое ИЛИ) и запятыми. Например, в выражении *p++ != 0 && *q++ != 0
все побочные эффекты подвыражения * p ++!= 0 завершены до любой попытки доступа к q.
Точка последовательности определяет любую точку в выполнении компьютерной программы, при которой гарантируется, что все побочные эффекты предыдущих оценок будут выполнены, и никаких побочных эффектов от последующих оценок еще не было выполнено.
Ответ 2
Да. Потому что оба оператора &&
и ||
также называются точками последовательности. Последние определяют, когда побочные эффекты предыдущей операции должны быть полными, а побочные эффекты следующего не должны начаться.
Ответ 3
Оценка в составном условии оператора if строго слева направо. Единственное обстоятельство, при котором второй тест в вашем if будет оптимизирован, - это если компилятор может определить со 100% уверенностью, что первый идентично равен false.