|
|
Порядок вычисления подвыражений, входящих в выражение, не всегда определен. Например:
int i = 1;
v[i] = i++;
Здесь выражение может вычисляться или как v[1]=1, или как v[2]=1.
Если нет ограничений на порядок вычисления подвыражений, то транслятор
получает возможность создавать более оптимальный код. Транслятору
следовало бы предупреждать о двусмысленных выражениях, но к сожалению
большинство из них не делает этого.
Для операций
&& || ,
гарантируется, что их левый операнд вычисляется раньше правого операнда. Например, в выражении b=(a=2,a+1) b присвоится значение 3. Пример операции || был дан в $$3.2.1, а пример операции && есть в $$3.3.1. Отметим, что операция запятая отличается по смыслу от той запятой, которая используется для разделения параметров при вызове функций. Пусть есть выражения:
f1(v[i],i++); // два параметра
f2( (v[i],i++) ) // один параметр
Вызов функции f1 происходит с двумя параметрами: v[i] и i++, но
порядок вычисления выражений параметров неопределен. Зависимость
вычисления значений фактических параметров от порядка вычислений
- далеко не лучший стиль программирования. К тому же программа
становится непереносимой.
Вызов f2 происходит с одним параметром, являющимся выражением,
содержащим операцию запятая: (v[i], i++). Оно эквивалентно i++.
Скобки могут принудительно задать порядок вычисления. Например,
a*(b/c) может вычисляться как (a*b)/c (если только пользователь
видит в этом какое-то различие). Заметим, что для значений с плавающей
точкой результаты вычисления выражений a*(b/c) и (a*b)/ могут
различаться весьма значительно.
| |