if(!feof(pf)) && (с = getc(pf)) …
Здесь feof— функция проверки на конец файла, getc— функция чтения символа из файла (см. раздел 12).
В-третьих, можно гарантировать, что в выражении f(x)&&g(y)функция fбудет вызвана раньше, чем функция g. Для выражения f(x)+g(y)этого утверждать нельзя.
В последующих примерах показано группирование операндов для различных выражений.
Выражение |
Группирование операндов |
a & b || c |
(a & b) || c |
a = b || c |
a = (b || c) |
q && r || s-- |
(q && r) || (s--) |
p == 0 ? p += 1 : p += 2 |
(p == 0 ? p += 1 : p) += 2 |
В первом примере поразрядная операция И (&) имеет больший приоритет, чем -логическая операция ИЛИ (||), поэтому выражение а&bявляется первым операндом логической операции ИЛИ.
Во втором примере логическая операция ИЛИ (||) имеет больший приоритет, чем операция простого присваивания, поэтому выражение b||собразует правый операнд операции присваивания. (Обратите внимание на то, что значение, присваиваемое а, есть нуль или единица.)
В третьем примере показано синтаксически корректное выражение, которое может выработать неожиданный результат. Логическая операция И (&&) имеет более высокий приоритет, чем логическая операция ИЛИ (||), поэтому запись q&&rобразует операнд. Поскольку логические операции сначала вычисляют свой левый операнд, то выражение q&&rвычисляется раньше, чем s--. Однако если q&&rдает ненулевое значение, то s--не будет вычисляться и sне декрементируется. Более надежно было бы поместить s--на место первого операнда выражения либо декрементировать sотдельной операцией.
В четвертом примере показано неверное выражение, которое приведет к ошибке при компиляции. Операция равенства (==) имеет наибольший приоритет, поэтому p==0группируется в операнд. Тернарная операция ?:имеет следующий приоритет. Ее первым операндом является выражение p==0, вторым операндом — выражение p+=1. Однако последним операндом тернарной операции будет считаться p, а не p+=2. так как в данном случае идентификатор pпо приоритету операций связан более тесно с тернарной операцией, чем с составной операцией сложения с присваиванием. В результате возникает синтаксическая ошибка, поскольку левый операнд составной операции присваивания не является L-выражением.
Чтобы предупредить ошибки подобного рода и сделать программу более наглядной, рекомендуется использовать скобки. Предыдущий пример может быть корректно оформлен следующим образом:
(р == 0) ? (р += 1) : (р += 2)
Побочный эффект выражается в неявном изменении значения переменной в процессе вычисления выражения. Все операции присваивания могут вызывать побочный эффект. Вызов функции, в которой изменяется значение какой-либо внешней переменной, либо путем явного присваивания, либо через указатель, также имеет побочный эффект.
Порядок вычисления выражения зависит от реализации компилятора, за исключением случаев, в которых явно гарантируется определенный порядок вычислений (см. раздел 4.5). При вычислении выражения в языке Си существуют так называемые контрольные точки. По достижении контрольной точки все предшествующие вычисления, в том числе все побочные эффекты, гарантированно произведены. Контрольными точками являются операция последовательного вычисления, условная операция, логические операции И и ИЛИ, вызов функции. Другие контрольные точки:
—конец полного выражения (т.е. выражения, которое не является частью другого выражения);
—конец инициализирующего выражения для переменной класса памяти auto;
—конец выражений, управляющих выполнением операторов if, switch, for, do, whileи выражения в операторе return. Приведем примеры побочных эффектов:
add(i + 1, i = j + 2);
Аргументы вызова функции addмогут быть вычислены в любом порядке. Выражение i+1может быть вычислено перед выражением i=j+2, или после него, с различным результатом в каждом случае.
Унарные операции инкремента и декремента также содержат в себе присваивание и могут быть причиной побочных эффектов, как это показано в следующем примере:
int i, а [10];
i = 0;
a[i++] = i;
Неизвестно, какое значение будет присвоено элементу а[0] — нуль или единица, поскольку для операции присваивания порядок вычисления аргументов не оговаривается.
Читать дальше