
\chapter{Типы, операторы и выражения}
\label{chapt:types-operators-expressions}

Переменные и константы являются основными объектами, с которыми имеет дело
программа. Переменные перечисляются в описаниях, где устанавливаются их типы, а
возможно, и начальные значения. Операции специфицируют те действия, которые с
ними совершаются. Для получения новых значений выражения могут оперировать с
переменными и константами. Тип объекта определяет множество значений, которые
этот объект может принимать, и операций, которые над ними могут выполняться.
Названные <<кирпичики>> и будут предметом обсуждения в этой главе.

Стандартом ANSI было утверждено значительное число небольших изменений и
добавлений к основным типам и выражениям. Любой целый тип теперь может быть со
знаком, \verb|signed|, и без знака, \verb|unsigned|. Предусмотрен способ записи
беззнаковых констант и шестнадцатеричных литерных констант. Операции с плавающей
точкой допускаются теперь и с одинарной точностью. Введён тип
\verb|long double|, обеспечивающий повышенную точность. Стринговые константы
конкатенируются (<<склеиваются>>) теперь во время компиляции. Перечислимый тип
стал частью языка, формализующей установку диапазона значений типа.
\index{const@\texttt{const}}%
Объекты разрешено помечать как \verb|const| для защиты их от каких-либо
изменений. В связи с введением новых типов расширены правила автоматического
преобразования из одного арифметического типа в другой.

\section{Имена переменных}

\index{переменная!синтаксис имени}%
\index{синтаксис имён переменных}%
Хотя мы ничего не говорили об этом в гл.~\ref{chapt:tutorial_intro}, но
существуют некоторые ограничения на задание имён переменных и именованных
констант. Имена составляются из букв и цифр; первой литерой должна быть буква.
\index{литера!подчёркивания \texttt{\_}}%
Знак подчёркивания <<\verb|_|>> считается буквой; его иногда удобно
использовать, чтобы улучшить восприятие длинных имён переменных. Не начинайте
имена переменных с подчёркивания, так как многие переменные библиотечных
программ начинаются именно с этого знака. Большие (прописные) и малые (строчные)
буквы различаются, так что \verb|x| и \verb|X| -- два разных имени. Обычно в
программах на Си малыми буквами набирают переменные, а большими -- именованные
константы.

\index{длина!имени}%
Для внутренних имён значимыми являются первые 31 литера.
\index{функция!длина имени}%
Для имён функций и внешних переменных число значимых литер может быть меньше 31,
так как эти имена обрабатываются ассемблерами и загрузчиками и языком не
контролируются. Уникальность внешних имён гарантируется только в пределах 6
литер, набранных безразлично в каком регистре. Ключевые слова \verb|if|,
\verb|else|, \verb|int|, \verb|float| и т.д. зарезервированы, и их нельзя
использовать в качестве имён переменных. Все они набираются на нижнем регистре
(т.е. малыми буквами).

Разумно переменным давать осмысленные имена в соответствии с их назначением,
причём такие, чтобы их было трудно спутать друг с другом. Мы предпочитаем
короткие имена для локальных переменных, особенно для счётчиков циклов, и более
длинные для внешних переменных.

\section{Типы и размеры данных}

\index{типы!базовые}%
\index{типы!плавающие}%
\index{типы!целочисленные}%
\index{целочисленные типы}%
\index{числа!размер}%
В Си существует всего лишь несколько базовых типов:

\begin{LongRtAlTab2cols}{\codeIndent}{0pt}{\Verb|double|}
\verb|char|%
\index{char@\texttt{char}!тип}%
&единичный байт, который может содержать одну литеру из допустимого набора
литер\\
\verb|int|%
\index{int@\texttt{int}!тип}%
&целое, обычно отображаемое на естественное представление целых в машине\\
\verb|float|%
\index{float@\texttt{float}!тип}%
&число с плавающей точкой одинарной точности\\
\verb|double|%
\index{double@\texttt{double}!тип}%
&число с плавающей точкой двойной точности
\end{LongRtAlTab2cols}

\index{long@\texttt{long}!тип}%
\index{short@\texttt{short}}%
Имеется также несколько квалификаторов, которые можно использовать вместе с
указанными базовыми типами. Например, квалификаторы \verb|short| (короткий) и
\verb|long| (длинный) применяются к целым:

\begin{ShortCodePar}
short int sh;
long int counter;
\end{ShortCodePar}

\noindent В таких описаниях слово \verb|int| можно опускать, что обычно и
делается.

Если только не возникает противоречий со здравым смыслом, целое \verb|short| и
целое \verb|long| должны быть разной длины, а \verb|int| соответствовать
естественному размеру целых на данной машине. Чаще всего для представления
целого, описанного с квалификатором \verb|short|, отводится 16 бит, с
квалификатором \verb|long| -- 32 бита, а значению типа \verb|int| -- или 16,
или 32 бита. Разработчики компилятора вправе сами выбирать подходящие размеры,
сообразуясь с характеристиками своего компьютера и соблюдая только следующие
ограничения: значения типов \verb|short| и \verb|int| представляются по крайней
мере 16 битами, типа \verb|long| -- по крайней мере 32 битами, размер
\verb|short| не больше размера \verb|int|, который в свою очередь не больше
размера \verb|long|.

\index{signed@\texttt{signed}!тип}%
\index{unsigned@\texttt{unsigned}!тип}%
\index{unsigned char, тип@\texttt{unsigned char}, тип}%
Квалификаторы \verb|signed| (со знаком) или \verb|unsigned| (без знака) можно
применять к типу \verb|char| и любому целому типу. Значения \verb|unsigned|
всегда положительны или равны нулю и подчиняются законам арифметики по модулю
$2^n$, где $n$ -- количество бит в представлении типа. Так, например, если
значению \verb|char| отводится 8 бит, то \verb|unsigned char| имеет значения в
диапазоне от $0$ до $255$, а \verb|signed char| -- от $-128$ до $127$ (в машине
с двоичным дополнительным кодом). Являются ли значения типа просто \verb|char|
знаковыми или беззнаковыми, зависит от машины, но в любом случае коды печатаемых
литер положительны.

\index{long double@\texttt{long double}!тип}%
Тип \verb|long double| предназначен для арифметики с плавающей точкой повышенной
точности. Как и в случае целых, размеры объектов с плавающей точкой зависят от
реализации; \verb|float|, \verb|double| и \verb|long double| могут
представляться одним размером, а могут -- двумя или тремя разными размерами.

\index{файл!головной!<float.h>@\texttt{<float.h>}}%
Именованные константы для всех размеров вместе с другими характеристиками машины
и компилятора содержатся в стандартных головных файлах
\verb|<limits.h>| и \verb|<float.h>|. (См.приложение~\ref{apx:stdlib}.)

\paragraph{Упражнение 2.1.} Напишите программу, которая будет выдавать диапазоны
значений типов \verb|char|, \verb|short|, \verb|int| и \verb|long|, описанных
как \verb|signed| и как \verb|unsigned|, с помощью печати соответствующих
значений из стандартных головных файлов и путём прямого вычисления. Определите
диапазоны чисел с плавающей точкой различных типов. Вычислить эти диапазоны
сложнее.

\section{Константы}
\label{sec:constants}

\index{константа}%
\index{константа!суффикс}%
\index{константа!тип}%
\index{суффикс в константе}%
\index{тип!константа}%
\index{целая константа}%
\index{int@\texttt{int}!константа}%
\index{signed@\texttt{signed}!константа}%
\index{unsigned@\texttt{unsigned}!константа}%
Целая константа, например, \verb|1234|, имеет тип \verb|int|.
\index{long@\texttt{long}!константа}%
\index{unsigned long, константа@\texttt{unsigned long}, константа}%
Константа типа \verb|long| завершается буквой \verb|l| или \verb|L|, например
\verb|123456789L|; слишком большое целое, которое невозможно представить как
\verb|int|, будет представлено как \verb|long|. Беззнаковые константы
заканчиваются буквой \verb|u| или \verb|U|, а окончание \verb|ul| или \verb|UL|
говорит о том, что тип константы -- \verb|unsigned long|.

\index{константа!с плавающей точкой}%
\index{экспонента в записи числа}%
\index{double@\texttt{double}!константа}%
\index{E (спецификатор экспоненты)@\texttt{E} (спецификатор экспоненты)}%
\index{float@\texttt{float}!константа}%
\index{long double@\texttt{long double}!константа}%
Константы с плавающей точкой имеют десятичную точку (\verb|123.4|) или
экспоненциальную часть (\verb|1e-2|) или же и то и другое. Если у них нет
окончания, считается, что они типа \verb|double|. Окончание \verb|f| или
\verb|F| указывает на тип \verb|float|, а \verb|l| или \verb|L| -- на тип
\verb|long double|.

Помимо десятичного целое значение может иметь восьмеричное или шестнадцатеричное
представление. 
\index{константа!восьмеричная \texttt{0}\ldots}%
\index{восьмеричная константа \texttt{0}\ldots}%
Если константа начинается с нуля, то она представлена в
восьмеричном виде, если с \verb|0x| или
\index{константа!шестнадцатеричная \texttt{0x}\ldots}%
\index{шестнадцатеричная константа \texttt{0x}\ldots}%
с \verb|0X|, то -- в шестнадцатеричном.
Например, десятичное целое \verb|31| можно записать как \verb|037| или как
\verb|0X1F|. Записи восьмеричной и шестнадцатеричной констант могут завершаться
буквой \verb|L| (для указания на тип \verb|long|) и \verb|U| (если нужно
показать, что константа беззнаковая). Например, константа \verb|0XFUL| имеет
значение $15$ и тип \verb|unsigned long|.
%
% исправлены орфографические ошибки
% в оригинале было
% "шестнадцатиричное", "шестнадцатиричном", "шестнадцатиричной"
%

\index{константа!литерная}%
\index{char@\texttt{char}!константа}%
\emph{Литерная константа} есть целое, записанное в виде литеры, обрамленной
одиночными кавычками, например \verb|'x'|.
\index{переносимость}%
Значением литерной константы является
числовой код литеры из набора литер на данной машине.
\index{литеры!набор!ASCII}%
\index{ASCII}%
Например, литерная константа \verb|'0'| в кодировке ASCII имеет значение $48$,
которое никакого отношения к числовому значению 0 не имеет. Если мы пишем
\verb|'0'|, а не какое-нибудь значение (например, $48$), которое следует из
способа кодировки, мы тем самым делаем программу независимой от частного
значения кода, к тому же она и легче читается. Литерные константы могут
участвовать в операциях над числами точно так же, как и любые другие целые, хотя
чаще они используются для сравнения с другими литерами.

\index{литера!новая-строка \texttt{\textbackslash n}}%
\index{эскейп-последовательность}%
\index{n@\texttt{\textbackslash n}}%
Некоторые литеры в литерных и стринговых константах записываются с помощью
эскейп-последовательностей, например \verb|\n| (новая-строка); такие
последовательности изображаются двумя литерами, но обозначают одну.
\index{константа!литерная!восьмеричная \texttt{\textbackslash\textit{ooo}}}%
\index{эскейп-последовательность!восьмеричная \texttt{\textbackslash\textit{ooo}}}%
Кроме того, произвольный восьмеричный код можно задать в виде

\begin{ShortCodeParWithCC}{+\{\}}
'\+textit{ooo}'
\end{ShortCodeParWithCC}

\noindent где \textit{ooo} -- одна, две или три восьмеричные цифры
(\verb|0|\ldots\verb|7|) или

\index{константа!литерная!шестнадцатеричная \texttt{\textbackslash x\textit{hh}}}%
\index{эскейп-последовательность!шестнадцатеричная \texttt{\textbackslash x\textit{hh}}}%
\begin{ShortCodeParWithCC}{+\{\}}
'\x+textit{hh}'
\end{ShortCodeParWithCC}

\noindent где \textit{hh} -- одна, две или более шестнадцатеричные цифры
(\verb|0|\ldots\verb|9|, \verb|a|\ldots\verb|f|‚ \verb|A|\ldots\verb|F|). Таким
образом, мы могли бы написать
%
% исправлена орфографическая ошибка
% в оригинале было "шестнадцатиричные"
%

\begin{ShortCodePar}
#define VTAB '\013'    /* верт. табуляция в ASCII */
#define BELL '\007'    /* звонок в ASCII */
\end{ShortCodePar}

\noindent или в шестнадцатеричном виде:
%
% исправлена орфографическая ошибка
% в оригинале было "шестнадцатиричном"
%

\begin{ShortCodePar}
#define VTAB '\xb'     /* верт. табуляция в ASCII */
#define BELL '\x7'     /* звонок в ASCII */
\end{ShortCodePar}

\noindent%
\index{эскейп-последовательность}%
Полный набор эскейп-последовательностей следующий:

\smallskip
\index{таблица!эскейп-последовательностей}%
{\setlength{\LTleft}{\codeIndent-\tabcolsep}%
\SetLenVarWithVal{\Halflen}{(\linewidth-\LTleft-\tabcolsep)/2}%
\SetLenVarWithWidth{\colAlen}{\Verb|\textbackslash a|}%
\SetLenVarWithWidth{\colClen}{\Verb|\textbackslash x|\textit{\Verb|hh|}}%
\noindent\hspace{\LTleft}\begin{tabular}
{p{\colAlen}p{\Halflen-6\tabcolsep-\colAlen}p{\colClen}p{\Halflen-\colClen}}
\verb|\a|%
\index{литера!сигнал-звонок \texttt{\textbackslash a}}%
\index{a@\texttt{\textbackslash a}}%
&сигнал-звонок&\verb|\\|%
\index{литера!обратная наклонная черта \texttt{\textbackslash\textbackslash}}%
&обратная-наклонная-черта\\
\verb|\b|%
\index{b (backspace)@\texttt{\textbackslash b} (backspace)}%
&возврат-на-шаг&\verb|\?|&знак-вопроса\\
\verb|\f|%
\index{литера!новая-страница \texttt{\textbackslash f}}%
\index{f литера новая-страница@\texttt{\textbackslash f} литера новая-страница}%
&перевод-страницы&\verb|\'|%
\index{литера!кавычка \texttt{'}}%
&одиночная-кавычка\\
\verb|\n|%
\index{литера!новая-строка \texttt{\textbackslash n}}%
\index{n@\texttt{\textbackslash n}}%
&новая-строка&\verb|\"|%
\index{литера!двойная кавычка \texttt{\char`\"}}%
&двойная-кавычка\\
\verb|\r|%
\index{литера!возврат каретки \texttt{\textbackslash r}}%
\index{r@\texttt{\textbackslash r}}%
&возврат-каретки
&\verb|\|\textit{\Verb|ooo|}%
\index{ooo@\texttt{\textbackslash\textit{ooo}}}%
&восьмеричный-код\\
\verb|\t|%
\index{t@\texttt{\textbackslash t}}%
&гор-табуляция
&\verb|\x|\textit{\Verb|hh|}%
\index{xhh шестнадцатеричная эскейп-последовательность@\texttt{\textbackslash x\textit{hh}} шестнадцатеричная эскейп-последовательность}%
&шестнадцатиричный-код\\
\verb|\v|%
\index{литера!вертикальная табуляция \texttt{\textbackslash v}}%
\index{v@\texttt{\textbackslash v}}%
&верт-табуляция	&&\\
\end{tabular}}
\smallskip

\index{null-литера, 0@null-литера, \texttt{\textbackslash 0}}%
Литерная константа \verb|'\0'| -- это литера с нулевым значением -- так
называемая литера null. Вместо просто 0 часто используют запись \verb|'\0'|‚
чтобы подчеркнуть литерную природу выражения, хотя и в том и другом случае
запись обозначает нуль.

\index{выражение!константное}%
\index{константное выражение}%
\emph{Константные выражения} -- это выражения, оперирующие только с константами.
Такие выражения вычисляются во время компиляции, а не во время счёта, и поэтому
их можно использовать в любом месте, где допустимы константы, как, например, в

\begin{ShortCodePar}
#define MAXLINE 1000
char line[MAXLINE+1];
\end{ShortCodePar}

\noindent или в

\begin{ShortCodePar}
#define LEAP 1 /* in leap years - в високосные годы */
int days[31+28+LEAP+31+30+31+30+31+31+30+31+30+31];
\end{ShortCodePar}

\index{константа!стринговая}%
\emph{Стринговая константа}, или \emph{стринговый литерал}, -- это нуль или
более литер, заключённых в двойные кавычки, как, например,

\begin{ShortCodePar}
"Это стринговая константа"
\end{ShortCodePar}

\noindent или

\index{стринг!пустой}%
\begin{ShortCodePar}
""   /* пустой стринг */
\end{ShortCodePar}

\noindent%
\index{стринг!длина}%
Кавычки не входят в стринг, а служат только её ограничителями. Так же,
как и в литерные константы, в стринги можно включать эскейп-последовательности;
\verb|\"|, например, представляет собой двойную кавычку.
\index{конкатенация!стрингов}%
\index{стринг!конкатенация}%
Стринговые константы можно конкатенировать (<<склеивать>>) во время компиляции;
например, запись двух стрингов

\begin{ShortCodePar}
"Здравствуй,"  " мир!"
\end{ShortCodePar}

\noindent эквивалентна записи одного следующего стринга:

\begin{ShortCodePar}
"Здравствуй, мир!"
\end{ShortCodePar}

\noindent Указанное свойство позволяет разбивать длинные стринги на части и
располагать эти части на отдельных строчках.

\index{длина!стринга}%
\index{стринг!длина}%
Фактически стринговая константа -- это массив литер. Во внутреннем представлении
стринга в конце обязательно присутствует null-литера \verb|'\0'|, поэтому памяти
для стринга требуется на один байт больше, чем число литер, расположенных между
двойными кавычками. Это означает, что нет ограничения на длину задаваемого
стринга, но чтобы определить его длину, требуется просмотреть весь стринг.
\index{функция!strlen@\texttt{strlen}}%
Функция \verb|strlen(s)| вычисляет длину стринга \verb|s| без учёта завершающей
его литеры \verb|'\0'|. Ниже приводится наша версия этой функции:

\begin{LongCodePar}
/* strlen: возвращает длину стринга  */
int strlen(char s[])
{
    int i;
    i = 0;
    while (s[i] != '\0')
        ++i;
    return i;
}
\end{LongCodePar}

\noindent%
\index{файл!головной!<string.h>@\texttt{<string.h>}}%
Функция \verb|strlen| и некоторые другие, применяемые к стрингам, описаны в
стандартном головном файле \verb|<string.h>|.

Будьте внимательны и помните, что литерная константа и стринг, содержащий одну
литеру, не одно и то же: \verb|'x'| не то же самое, что \verb|"x"|. Запись
\verb|'x'| обозначает целое значение, равное коду буквы \verb|x| из стандартного
набора литер, а запись \verb|"x"| -- массив литер, который содержит одну литеру
(букву \verb|x|) и \verb|'\0'|.

\index{константа!перечисления}%
\index{перечисление!константа}%
\index{спецификатор!enum@\texttt{enum}}%
\index{enum@\texttt{enum}!спецификатор}%
В Си имеется ещё один вид константы, \emph{константа перечисления}. Перечисление
-- это список целых констант, как, например, в

\begin{ShortCodePar}
enum boolean { NO, YES };
\end{ShortCodePar}

\noindent Первое имя в \verb|enum|\footnote{От английского слова enumeration --
перечисление. -- \textit{Примеч. ред.}} имеет значение $0$, следующее -- $1$ и
т.д. (если не было явных спецификаций значений констант). Если не все значения
специфицированы, то они продолжают прогрессию, начиная от последнего
специфицированного значения, как в следующих двух примерах:

\begin{ShortCodePar}
enum escapes { BELL = '\a', BACKSPACE = '\b', TAB = '\t',
               NEWLINE = '\n', VTAB = '\v', RETURN = '\r' };
enum months { JAN = 1, FEB, MAR, APR, MAY, JUN,
              JUL, AUG, SEP, OCT, NOV, DEC };
              /* FEB есть 2, MAR есть 3 и т.д.  */
\end{ShortCodePar}

\noindent Имена в различных перечислениях должны отличаться друг от друга.
Значения внутри одного перечисления могут совпадать.

\index{define@\texttt{{\#}define}!вместо \texttt{enum}}%
\index{enum@\texttt{enum}!а не \texttt{{\#}define}}%
Средство \verb|enum| обеспечивает удобный способ присвоить константам имена,
причём в отличие от \verb|#define| при этом способе значения констант могут
генерироваться автоматически. Перечислимый тип разрешено использовать для
определения переменных, однако компилятор не обязан контролировать, входят ли
присваиваемые этим переменным значения в их тип. Но сама возможность такой
проверки часто делает \verb|enum| лучше, чем \verb|#define|. Кроме того,
отладчик получает возможность печатать значения перечислимых переменных в
символьном виде.

\section{Декларации}

\index{декларация}%
Все переменные должны быть декларированы раньше, чем будут использоваться, при
этом некоторые декларации могут быть получены неявно -- из контекста. Декларация
специфицирует тип и содержит список из одной или нескольких переменных этого
типа, как, например, в

\begin{ShortCodePar}
int lower, upper, step;
char c, line[1000];
\end{ShortCodePar}

\noindent%
\index{программа!формат}%
Переменные можно распределять по декларациям произвольным образом, так что
указанные выше списки можно записать и в следующем виде:

\begin{ShortCodePar}
int  lower;
int  upper;
int  step;
char c;
char line[1000];
\end{ShortCodePar}

Эта последняя форма записи занимает больше места, тем не менее она лучше‚
поскольку позволяет добавлять к каждой декларации комментарий и более удобна для
последующих модификаций.

\index{инициализация}%
\index{инициализация!переменных!автоматических}%
В своей декларации переменная может быть инициализирована, как, например:

\begin{ShortCodePar}
char  esc = '\\';
int   i = 0;
int   limit = MAXLINE+1;
float eps = 1.0e-5;
\end{ShortCodePar}

Инициализация неавтоматической переменной осуществляется только один раз --
перед тем, как программа начнёт выполняться, при этом инициализатор должен быть
константным выражением. Явно инициализируемая автоматическая переменная получает
начальное значение каждый раз при входе в функцию или блок, её инициализатором
может быть любое выражение.
\index{инициализация!переменных!внешних}%
\index{инициализация!переменных!статических}%
Внешние и статические переменные по умолчанию получают нулевые значения.
Автоматические переменные, явным образом не инициализированные, содержат
неопределённые значения (<<мусор>>).

К любой переменной в декларации может быть применён квалификатор \verb|const|
для указания того, что её значение далее не будет изменяться.

\begin{ShortCodePar}
const double e = 2.71828182845905;
const char msg[] = "предупреждение: ";
\end{ShortCodePar}

\noindent Применительно к массиву квалификатор \verb|const| указывает на то, что
ни один из его элементов не будет меняться. Указание \verb|const| можно также
применять к аргументу-массиву, чтобы сообщить, что функция не изменяет этот
массив:

\begin{ShortCodePar}
int strlen(const char[]);
\end{ShortCodePar}

\noindent Реакция на попытку изменить переменную, помеченную квалификатором
\verb|const|, оставлена на усмотрение компилятора.

\section{Арифметические операторы}

\index{оператор!вычитания \texttt{\textminus}}%
\index{оператор!деления \texttt{\slash}}%
\index{оператор!деления по модулю \texttt{\%}}%
\index{оператор!сложения \texttt{+}}%
\index{оператор!умножения \texttt{*}}%
\index{операторы!арифметические}%
Бинарными арифметическими операторами являются \verb|+|, \verb|-|‚ \verb|*|,
\verb|/|‚ а также оператор взятия модуля \verb|%|.
\index{деление целых}%
Деление целых сопровождается отбрасыванием дробной части, какой бы она ни была.
Выражение

\begin{ShortCodePar}
x%y
\end{ShortCodePar}

\noindent даёт остаток от деления \verb|x| на \verb|y| и, следовательно, нуль,
если \verb|x| делится на \verb|y| нацело. Например,
\index{високосный год, вычисление}%
год является високосным, если он делится на $4$ (но не на $100$). Кроме того,
високосным считается год, если он делится на $400$. Следовательно,

\begin{ShortCodePar}
if ((year % 4 == 0 && year % 100 != 0 || year % 400 == 0)
    printf(”%d високосный год\n, year);
else
    printf("%d не високосный год\n, year);
\end{ShortCodePar}

\noindent Оператор \verb|%| к операндам типов \verb|float| и \verb|double| не
применяется.
\index{обрезание!при делении}%
В какую сторону (в сторону увеличения или уменьшения числа) будет усечена
дробная часть при выполнении \verb|/| и каким будет знак результата операции
\verb|%| с отрицательными операндами, это зависит от машины.

Бинарные операторы \verb|+| и \verb|-| имеют одинаковый приоритет, который ниже
приоритета операторов \verb|*|, \verb|/| и \verb|%|, который в свою очередь ниже
приоритета унарных операторов \verb|+| и \verb|-|. Арифметические операции
одного приоритетного уровня выполняются слева направо.

В конце этой главы приводится табл.~\ref{tab:precedence}, в которой показаны
приоритеты всех операторов и порядок их выполнения.

\section{Операторы отношения и логические операторы}

\index{оператор!меньше или равно \texttt{\textless=}}%
\index{оператор!меньше \texttt{\textless}}%
\index{оператор!больше или равно \texttt{\textgreater=}}%
\index{оператор!больше \texttt{\textgreater}}%
\index{оператор!неравенства \texttt{"!=}}%
\index{оператор!равенства \texttt{==}}%
\index{операторы!отношения}%
\index{операторы!равенства}%
Операторами отношения являются

\begin{ShortCodePar}
>   >=   <   <=
\end{ShortCodePar}

\noindent Все они имеют одинаковый приоритет. Ровно на одну ступень ниже
приоритета операторов сравнения на равенство:

\begin{ShortCodePar}
==   !=
\end{ShortCodePar}

\noindent Операторы отношения имеют более низкий приоритет, чем арифметические,
поэтому выражение типа \verb|i < lim-1| будет выполняться так же, как
\verb|i < (lim-1)|, т.е. как мы и ожидаем.

\index{оператор!логического И \texttt{\&\&}}%
\index{оператор!логического ИЛИ \texttt{"|"|}}%
Более интересны логические операторы \verb|&&| и \verb+||+. Выражения, между
которыми стоят операторы \verb|&&| или \verb+||+, вычисляются слева направо, и
вычисление прекращается, как только становится известна истинность или ложность
результата. Многие Си-программы опираются на это свойство, как, например, цикл
из функции \verb|getline| ‚ которую мы приводили в
гл.~\ref{chapt:tutorial_intro}:

\begin{ShortCodePar}
for (i=0; i<lim-1 && (c=getchar()) != '\n' && c != EOF; ++i)
    s[i] = c;
\end{ShortCodePar}

Прежде чем читать очередную литеру, нужно проверить, есть ли место для неё в
массиве \verb|s|, иначе говоря, сначала необходимо проверить условие
\verb|i < lim-1|. Если это условие не выполняется, мы не должны продолжать
вычисление, в частности читать следующую литеру. Так же было бы неправильным
сравнивать \verb|c| с \verb|EOF| до обращения к \verb|getchar|; следовательно, и
вызов \verb|getchar| и присваивание должны выполняться перед указанной
проверкой.

Приоритет оператора \verb|&&| выше, чем оператора \verb+||+, однако их
приоритеты ниже, чем приоритет операторов отношения и равенства; поэтому
выражение вида

\begin{ShortCodePar}
i<lim-1 && (c = getchar()) != '\n' && c != EOF
\end{ShortCodePar}

\noindent не нуждается в дополнительных скобках. Но,
\index{оператор!присваивания \texttt{=}}%
\index{операторы!присваивания}%
так как приоритет \verb|!=| выше, чем приоритет присваивания, в

\begin{ShortCodePar}
(c = getchar()) != '\n'
\end{ShortCodePar}

\noindent скобки необходимы, чтобы сначала выполнить присваивание, а затем
сравнение с \verb|n|.

\index{численное значение!выражения отношения}%
По определению численным результатом вычисления выражения отношения или
логического является $1$ в случае, если оно истинно, и $0$ в случае, если оно
ложно.

\index{оператор!логического отрицания \texttt{"!}}%
Унарный оператор \verb|!| преобразует ненулевой операнд в $0$, а нуль в $1$.
Обычно оператор \verb|!|, используют в конструкциях вида

\begin{ShortCodePar}
if (!valid)
\end{ShortCodePar}

\noindent что эквивалентно

\begin{ShortCodePar}
if (valid == 0)
\end{ShortCodePar}

\noindent Трудно сказать, какая из форм записи лучше. Конструкция вида
\verb|!valid| хорошо читается (<<если не \verb|valid|>>)‚ но в случае более
сложных выражений может оказаться, что её не так-то легко понять.

\paragraph{Упражнение 2.2.} Напишите цикл, эквивалентный приведённому выше
\verb|for|-циклу, не пользуясь операторами \verb|&&| и \verb+||+.

\section{Преобразования типов}
\label{chapt:types-operators-expressions:sec:typecasting}

\index{преобразование!обычное арифметическое}%
\index{тип!правила преобразования|(}%
Если операнды оператора принадлежат разным типам, то они приводятся к некоторому
общему типу. Приведение выполняется в соответствии с небольшим числом правил.
Обычно автоматически производятся лишь те преобразования, которые без какой-либо
потери информации превращают операнды с меньшим диапазоном значений в операнды с
большим диапазоном значений, как, например, преобразование целого в число с
плавающей точкой в выражении вроде \verb|f + i|. Выражения, не имеющие смысла,
например число с плавающей точкой в роли индекса, не допускаются. Выражения, в
которых могла бы теряться информация (скажем, при присваивании длинных целых
переменным более коротких типов или при присваивании значений с плавающей точкой
целым переменным), могут повлечь предупреждение, но они допустимы.

\index{преобразование!литера -- целое}%
Значения типа \verb|char| -- это всего лишь малые целые, и их можно свободно
использовать в арифметических выражениях, что значительно облегчает
всевозможные манипуляции с литерами.
\index{функция!atoi@\texttt{atoi}}%
В качестве примера приведём простенькую реализацию функции \verb|atoi|,
преобразующей последовательность цифр в её числовой эквивалент.

\begin{LongCodePar}
/* atoi: преобразование s в целое */
int atoi(char s[])
{
    int i, n;
    n = 0;
    for (i = 0; s[i] >= '0' && s[i] <= '9'; ++i)
        n = 10 * n + (s[i] - '0');
    return n;
}
\end{LongCodePar}

Как мы уже говорили в гл.~\ref{chapt:tutorial_intro}, выражение

\begin{ShortCodePar}
s[i] - '0'
\end{ShortCodePar}

\noindent даёт числовое значение литеры хранящейся в \verb|s[i]|‚ так как
значения \verb|'0'|, \verb|'1'| и т.д. образуют непрерывную возрастающую
последовательность.

\index{преобразование!литера -- целое}%
\index{функция!lower@\texttt{lower}}%
Другой пример приведения \verb|char| к \verb|int| связан с функцией 
\verb|lower|, которая одиночную литеру из набора ASCII, если она является 
заглавной буквой, превращает в прописную. Если же литера не является заглавной 
буквой, \verb|lower| её не изменяет.

\begin{LongCodePar}
/* lower:  преобразование c в строчную; только для ASCII */
int lower(int c)
{
    if (c >= 'A' && c <= 'Z')
        return c + 'a' - 'A';
    else
        return c;
}
\end{LongCodePar}
%%
%% в оригинале отсутствует закрывающая фигурная скобка
%%

\noindent%
\index{литеры!набор!ASCII}%
\index{переносимость}%
\index{ASCII}%
В случае ASCII эта программа будет правильно работать потому, что между
одноимёнными буквами верхнего и нижнего регистров -- одинаковое расстояние (если
их рассматривать как числовые значения), и, кроме того, латинский алфавит --
плотный в том смысле, что между буквами A и Z ничего кроме букв не существует.
\index{литеры!набор!EBCDIC}%
\index{EBCDIC}%
Для набора EBCDIC последнее условие не выполняется, и поэтому наша программа в
этом случае будет преобразовывать не только буквы.

\index{файл!головной!<ctype.h>@\texttt{<ctype.h>}}%
Стандартный головной файл \verb|<ctype.h>|‚ описанный в
приложении~\ref{apx:stdlib}, определяет семейство функций, которые позволяют
проверять и преобразовывать литеры независимо от набора литер. Например, функция
\verb|tolower(c)| возвращает букву \verb|c| в коде нижнего регистра, если она
была в коде верхнего регистра, поэтому \verb|tolower(c)| -- универсальная
замена функции \verb|lower(c)|, рассмотренной выше. Аналогично проверку

\begin{ShortCodePar}
c >= '0' && c <='9'
\end{ShortCodePar}

\noindent можно заменить на

\begin{ShortCodePar}
isdigit(c)
\end{ShortCodePar}

\noindent Далее мы будем пользоваться функциями из \verb|<ctype.h>|.

\index{литера!знаковая}%
\index{литера!беззнаковая}%
\index{оператор!приведения к типу}%
\index{переносимость}%
\index{повышение!типа аргумента}%
\index{повышение!целочисленного типа}%
\index{преобразование!литера -- целое}%
\index{преобразование!оператором приведения}%
\index{приведение к типу}%
\index{целочисленное повышение}%
Существует одна тонкость, касающаяся преобразования литер в целые: язык не
определяет, являются ли переменные типа \verb|char| знаковыми или беззнаковыми.
При преобразовании \verb|char| в \verb|int| может когда-нибудь получиться
отрицательное целое? На машинах с разной архитектурой ответы могут отличаться.
\index{знак, размножение}%
На некоторых машинах значение типа \verb|char| с единичным старшим битом будет
превращено в отрицательное целое (посредством <<размножения знака>>). На других
-- преобразование \verb|char| в \verb|int| осуществляется добавлением нулей
слева, и, таким образом, получаемое значение всегда положительно.

Гарантируется, что любая литера из стандартного набора печатаемых литер никогда
не будет отрицательным числом, поэтому в выражениях такие литеры всегда являются
положительными операндами. Но произвольный восьмибитовый код в переменной типа
\verb|char| на одних машинах может быть отрицательным числом, а на других --
положительным. Для совместимости переменные типа \verb|char|, в которых хранятся
нелитерные данные, следует специфицировать явно как \verb|signed| или
\verb|unsigned|.

\index{операторы!отношения}%
Отношения типа \verb|i > j| и
\index{выражение!логическое, численное значение}%
\index{численное значение!выражения отношения}%
\index{численное значение!логического выражения}%
логические выражения, перемежаемые операторами \verb|&&| и \verb!||!, определяют
выражение-условие, которое имеет значение $1$, если оно истинно, и $0$, если
ложно. Так, присваивание

\begin{ShortCodePar}
d = c >='0' && c <= '9'
\end{ShortCodePar}

\noindent установит в \verb|d| значение $1$, если \verb|c| есть цифра, и $0$ в
противном случае. Однако функции, подобные \verb|isdigit|, в случае истины могут
выдавать любое ненулевое значение. В местах проверок внутри \verb|if|,
\verb|while|, \verb|for| и т.д. <<истина>> просто означает <<не нуль>>.

\index{оператор!приведения к типу}%
\index{повышение!типа аргумента}%
\index{повышение!целочисленного типа}%
\index{преобразование!обычное арифметическое}%
\index{преобразование!целое -- плавающее}%
\index{преобразование!\texttt{float} -- \texttt{double}}%
\index{целочисленное повышение}%
Неявные арифметические преобразования, как правило, осуществляются естественным
образом. В общем случае, когда оператор типа \verb|+| или \verb|*| с двумя
операндами (бинарный оператор) имеет разнотипные операнды, прежде чем операция
начнёт выполняться, <<младший>> тип \emph{подтягивается} к <<старшему>>.
Результат будет иметь старший тип. В разд.~\ref{apx:sec:type_conversion}
приложения~\ref{apx:ref_manual} правила преобразования сформулированы точно.
Если же в выражении нет беззнаковых операндов, можно удовлетвориться следующим
набором неформальных правил:
\begin{itemize}
  \item Если какой-либо из операндов принадлежит типу \verb|long double|, то
  другой приводится к \verb|long double|.
  \item В противном случае, если какой-либо из операндов принадлежит типу
  \verb|double|, то другой приводится к \verb|double|.
  \item В противном случае, если какой-либо из операндов принадлежит типу
  \verb|float|, то другой приводится к \verb|float|.
  \item В противном случае операнды типов \verb|char| и \verb|short| приводятся
  к \verb|int|.
  \item И наконец, если один из операндов типа \verb|long|, то другой приводится
  к \verb|long|.
\end{itemize}

\index{преобразование!\texttt{float} -- \texttt{double}}%
Заметим, что операнды типа \verb|float| не приводятся автоматически к типу
\verb|double|; в этом данная версия языка отличается от первоначальной.
\index{файл!головной!<math.h>@\texttt{<math.h>}}%
Вообще говоря, математические функции, аналогичные собранным в библиотеке
\verb|<math.h>|, базируются на вычислениях с двойной точностью. В основном
\verb|float| используется для экономии памяти на больших массивах и менее часто
для убыстрения счёта на тех машинах, где арифметика двойной точности слишком
дорога.

Правила преобразования усложняются с появлением \verb|unsigned|-операндов.
Проблема в том, что сравнения знаковых и беззнаковых значений зависят от
размеров целых типов, которые на разных машинах могут отличаться. Предположим,
что значение типа \verb|int| занимает 16 бит, а значение типа \verb|long| -- 32
бита. Тогда \verb|-1L < 1U|, поскольку \verb|1U| принадлежит типу \verb|int| и
подтягивается к типу \verb|signed long|. Но \verb|-1L > 1UL|, так как
\verb|-1L| подтягивается к типу \verb|unsigned long| и воспринимается как
большое положительное число.

\index{преобразование!присваиванием}%
Преобразования имеют место и при присваиваниях: значение правой части
присваивания приводится к типу левой части, который и является типом результата.

\index{преобразование!литера -- целое}%
Литера превращается в целое посредством
\index{знак, размножение}%
размножения знака или другим описанным выше способом.

\index{преобразование!целое -- литера}%
Длинные целые преобразуются в короткие целые или в значения типа \verb|char| с
помощью отбрасывания старших разрядов. Так, в

\begin{ShortCodePar}
int  i;
char c;
i = c;
c = i;
\end{ShortCodePar} 

\noindent значение \verb|c| не изменится. Это справедливо независимо от того,
размножается знак при переводе \verb|char| в \verb|int| или нет. Однако, если
изменить порядок присваиваний, возможна потеря информации.

\index{обрезание!значения с плавающей точкой}%
\index{преобразование!плавающее -- целое}%
\index{преобразование!\texttt{double} -- \texttt{float}}%
Если \verb|x|  принадлежит типу \verb|float|, а \verb|i| типу \verb|float|, то и
\verb|x = i|, и \verb|i = x| вызовут преобразования, причём перевод \verb|float|
в \verb|int| сопровождается отбрасыванием дробной части. Если \verb|double|
переводится в \verb|float|, то значение либо округляется, либо обрезается; это
зависит от реализации.

\index{преобразование!\texttt{float} -- \texttt{double}}%
Так как аргумент в вызове функции есть выражение, при передаче его функции также
возможно преобразование типа. При отсутствии прототипа функции аргументы типа
\verb|char| и \verb|short| переводятся в \verb|int|, а \verb|float| -- в
\verb|double|. Вот почему мы объявляли аргументы типа \verb|int| или
\verb|double| даже тогда, когда в вызове функции использовали аргументы типа
\verb|char| или \verb|float|.

\index{преобразование!оператором приведения}%
И наконец, для любого выражения можно явно указать преобразование его типа,
используя унарный оператор, называемый \emph{приведением}. Конструкция вида

\begin{ShortCodeParWithCC}{\\\[\]}
(\textit[имя-типа]) \textit[выражение]
\end{ShortCodeParWithCC}

\noindent приводит \textit{выражение} к указанному в скобках типу по
перечисленным выше правилам. Смысл операции приведения можно представить себе
так: \textit{выражение} как бы присваивается некоторой переменной указанного
типа, и эта переменная используется вместо всей конструкции. Например,
библиотечная программа \verb|sqrt| рассчитана на аргумент типа \verb|double| и
выдаёт чепуху, если ей подсунуть что-нибудь другое. (\verb|sqrt| описана в
\verb|<math.h>|.) Поэтому, если \verb|n| есть целое, мы можем написать

\begin{ShortCodePar}
sqrt((double) n)
\end{ShortCodePar}

\noindent и перед тем, как значение \verb|n| будет передано функции, оно будет
переведено в \verb|double|. Заметим, что операция приведения всего лишь
вырабатывает \emph{значение} \verb|n| указанного типа, но саму переменную
\verb|n| не затрагивает. Приоритет оператора приведения столь же высок, как и
любого унарного оператора, что зафиксировано в таблице, показанной в конце этой
главы.

\index{прототип функции}%
\index{функция!прототип}%
В том случае, когда аргументы описаны в прототипе функции, как тому и следует
быть, при вызове функции нужное преобразование включается автоматически. Так,
при наличии прототипа функции \verb|sqrt|:

\begin{ShortCodePar}
double sqrt(double);
\end{ShortCodePar}

\noindent перед обращением к \verb|sqrt| в присваивании 

\begin{ShortCodePar}
root2 = sqrt(2);
\end{ShortCodePar} 

\noindent целое $2$ будет переведено в значение \verb|double| $2.0$
автоматически без явного указания операции приведения.

\index{функция!rand@\texttt{rand}}%
\index{функция!srand@\texttt{srand}}%
Операцию приведения проиллюстрируем на переносимой версии генератора
псевдослучайных чисел и функции, осуществляющей начальную <<затравку>>, входящих
в стандартную библиотеку.

\begin{LongCodePar}
unsigned long int next = 1;

/* rand:  получает псевдослучайное целое 0..32767 */
int rand(void)
{
    next = next * 1103515245 + 12345;
    return (unsigned int)(next/65536) % 32768;
}
/* srand:  устанавливает "затравку" для rand() */
void srand(unsigned int seed)
{
    next = seed;
}
\end{LongCodePar}
\index{тип!правила преобразования|)}%


\paragraph{Упражнение 2.3.} Напишите функцию \verb|htoi(s)|, которая преобразует
последовательность шестнадцатиричных цифр, начинающуюся с \verb|0x| или
\verb|0X|  в соответствующее целое. Шестнадцатиричными цифрами являются литеры
\verb|0...9|, \verb|a...f|, \verb|A...F|.

\section{Инкрементные и декрементные операторы}

\index{оператор!инкрементации \texttt{++}}%
\index{оператор!декрементации \texttt{\textminus\textminus}}%
В Си есть два необычных оператора, предназначенных для увеличения и уменьшения
переменных. Инкрементный оператор \verb|++| добавляет $1$ к своему операнду, а
декрементный оператор \verb|--| вычитает $1$. Мы уже неоднократно использовали
\verb|++| для наращивания значения переменных, как, например, в

\begin{ShortCodePar}
if (c == '\n')
    ++nl;
\end{ShortCodePar}

\index{операторы!постфиксные \texttt{++} и \texttt{\textminus\textminus}}%
\index{операторы!префиксные \texttt{++} и \texttt{\textminus\textminus}}%
Необычность \verb|++| и \verb|--| в том, что их можно использовать и как
префиксные операторы (помещая перед переменной, например, \verb|++n|), и как
постфиксные операторы (помещая после переменной: \verb|n++|) . В обоих случаях
значение \verb|n| увеличивается на $1$. Но выражение \verb|++n| увеличивает
\verb|n| \emph{до} того, как его значение будет использовано, а \verb|n++| --
\emph{после} того. Предположим, что \verb|n| содержит $5$, тогда

\begin{ShortCodePar}
x = n++;
\end{ShortCodePar}

\noindent установит в \verb|x| значение $5$, а

\begin{ShortCodePar}
x = ++n;
\end{ShortCodePar}

\noindent установит в \verb|x| значение $6$. И в том и другом случае значение
\verb|n| станет равным $6$. Инкрементные и декрементные операторы можно
применять только к переменным. Например, запись \verb|(i+j)++| не верна. В
контексте, где требуется только увеличить (или уменьшить) значение переменной,
как в

\begin{ShortCodePar}
if (c == '\n')
    nl++;
\end{ShortCodePar} 

\noindent безразлично, какой выбрать оператор -- префиксный или постфиксный. Но
существуют ситуации, когда требуется оператор вполне определённого типа.
\index{функция!squeeze@\texttt{squeeze}}%
Например, рассмотрим функцию \verb|squeeze(s,c)|, которая удаляет из стринга
\verb|s| все литеры, совпадающие с \verb|c|:

\begin{LongCodePar}
/* squeeze:  удаляет все c из s */
void squeeze(char s[], int c)
{
    int i, j;
    for (i = j = 0; s[i] != '\0'; i++)
        if (s[i] != c)
            s[j++] = s[i];
    s[i] = '\0';
}
\end{LongCodePar}
%
% в оригинале опечатка squeese
%

\noindent Каждый раз, когда встречается литера, отличная от \verb|c|, она
копируется в текущую \verb|j|-ю позицию, и только после этого переменная
\verb|j| продвигается на 1, подготавливаясь таким образом к приёму следующей
литеры. Это в точности совпадает со следующими действиями:

\begin{ShortCodePar}
if (s[i] != c) {
    s[j] = s[i];
    j++;
}
\end{ShortCodePar} 

Другой пример -- функция \verb|getline|, которая нам известна по
гл.~\ref{chapt:tutorial_intro}. Приведённую там запись

\begin{ShortCodePar}
if (c == '\n') {
    s[i] = c;
    ++i;
}
\end{ShortCodePar} 

\noindent можно переписать более компактно:

\begin{ShortCodePar}
if (c == '\n')
    s[i++] = c;
\end{ShortCodePar}

\index{функция!strcat@\texttt{strcat}}%
В качестве третьего примера рассмотрим стандартную функцию \verb|strcat(s,t)|,
которая стринг \verb|t| помещает в конец стринга \verb|s|. Предполагается, что в
\verb|s| достаточно пространства, чтобы в нём разместить суммарный стринг. Мы
написали \verb|strcat| так, что она не возвращает никакого результата. На самом
деле библиотечная \verb|strcat| возвращает ссылку на результирующий стринг.

\begin{ShortCodePar}
/* strcat: помещает t в конец s; s достаточно большой */
void strcat(char s[], char t[])
{
    int i,j;

    i = j = 0;
    while (s[i] != '\0')  /* находим конец s */
        i++;
    while ((s[i++] = t[j++]) != '\0' /* копируем t */
        ;
}
\end{ShortCodePar}

\noindent При копировании очередной литеры из \verb|t| в \verb|s| постфиксный
оператор \verb|++| применяется и к \verb|i|, и к \verb|j|, чтобы на каждом шаге
цикла переменные \verb|i| и \verb|j| правильно отслеживали позиции перемещаемой
литеры.

\paragraph{Упражнение 2.4.} Напишите версию функции \verb|squeeze(s1,s2)|,
которая удаляет из \verb|s1| все литеры, встречающиеся в \emph{стринге}
\verb|s2|.
%
% в оригинале опечатка squeese
%

\paragraph{Упражнение 2.5.} Напишите функцию \verb|any(s1,s2)|, которая
возвращает либо ту позицию в \verb|s1|, где стоит первая литера, совпавшая с
любой из литер в \verb|s2|, либо $-1$ (если ни одна литера \verb|s1| не
совпадает с литерами из \verb|s2|). (Стандартная библиотечная функция
\verb|strpbrk| делает то же самое, но выдаёт указатель на литеру, а не номер её
позиции.)

\section{Побитовые операторы}

\index{биты, образцы манипулирования}%
\index{оператор!дополнения побитового до единиц \texttt{\textasciitilde}}%
\index{оператор!левого сдвига \texttt{\textless}\texttt{\textless}}%
\index{оператор!правого сдвига \texttt{\textgreater}\texttt{\textgreater}}%
\index{операторы!побитовые}%
\index{операторы!сдвига}%
В Си имеются шесть операторов для манипулирования с битами. Их можно применять
только к целочисленным операндам, т.е. к операндам типов \verb|char|,
\verb|short|, \verb|int|, \verb|long|, знаковым и беззнаковым.

\begin{LongRtAlTab2cols}{\codeIndent}{0pt}{\Verb|<<<<<<<<<<|}
\verb|&|   &побитовое И\\
\verb!|!   &побитовое ИЛИ\\
\verb|^|   &побитовое исключающее ИЛИ\\
\verb|<<|  &сдвиг влево\\
\verb|>>|  &сдвиг вправо\\
\verb|~|   &побитовое отрицание (унарный)
\end{LongRtAlTab2cols}

Оператор \verb|&| (побитовое И) часто используется для обнуления некоторой
группы разрядов. Например, 

\begin{ShortCodePar}
n = n & 0177;
\end{ShortCodePar} 

\noindent очищает в \verb|n| все разряды, кроме младших семи. 

Оператор \verb!|! (побитовое ИЛИ) применяют для установки разрядов; так, 

\begin{ShortCodePar}
x = x | SET_ON;
\end{ShortCodePar} 

\noindent устанавливает единицы в тех разрядах \verb|x|, которым соответствуют
единицы в \verb|SET_ON|.

Оператор \verb|^| (побитовое исключающее ИЛИ) в каждом разряде установит $1$,
если соответствующие разряды операндов имеют различные значения, и $0$, когда
они совпадают.

\index{оператор!логического И \texttt{\&\&}}%
\index{оператор!логического ИЛИ \texttt{"|"|}}%
Поразрядные операторы \verb|&| и \verb!|! следует отличать от логических
операторов \verb|&&| и \verb!||!, которые при
\index{вычисление, порядок}%
\index{порядок!вычислений}%
вычислении слева направо дают значение истинности. Например, если \verb|x| есть
$1$, а \verb|y| равно $2$, то \verb|x & y| даст нуль, а \verb|x && y| --
единицу.

Операторы \verb|<<| и \verb|>>| выполняют сдвиг, влево или вправо, своего левого
операнда на число битовых позиций, задаваемое правым операндом, которое должно
быть положительным. Так, \verb|x << 2| сдвигает значение \verb|x| влево на 2
позиции, заполняя освобождающиеся биты нулями, что эквивалентно умножению
\verb|x| на $4$. Сдвиг вправо беззнаковой величины всегда сопровождается
заполнением освобождающихся разрядов нулями. Сдвиг вправо знаковой величины на
одних машинах происходит с размножением знака (<<арифметический сдвиг>>), на
других -- с заполнением освобождающихся разрядов нулями (<<логический сдвиг>>).

Унарный оператор \verb|~| производит дополнение целого до единиц по всем
разрядам, т. е. превращает единичные биты в нулевые и наоборот. Например,

\begin{ShortCodePar}
x = x & ~077
\end{ShortCodePar} 

\noindent обнуляет в \verb|x| последние 6 разрядов. Заметим, что запись
\verb|x & ~077| не зависит от длины слова, и, следовательно, она лучше, чем
\verb|x & 0177700|, поскольку последняя подразумевает, что \verb|x| занимает 16
бит. Независимая от машины форма записи \verb|~077| не потребует дополнительных
затрат при счёте, так как \verb|~077| -- константное выражение, которое будет
вычислено во время компиляции.

\index{биты, образцы манипулирования}%
\index{функция!getbits@\texttt{getbits}}%
Для иллюстрации некоторых побитовых операций рассмотрим функцию
\verb|getbits(x,p,n)|, которая формирует поле в \verb|n| бит, вырезанное из
\verb|x|, начиная с позиции \verb|p|, прижимая его к правому краю.
Предполагается, что 0-й бит -- крайний правый бит, а \verb|n| и \verb|p| --
разумные положительные числа. Например, \verb|getbits(x,4,3)| вернёт в качестве
результата 4, 3 и 2-й биты значения \verb|x|, прижимая их к правому краю. Вот
эта функция:

\begin{ShortCodePar}
/* getbits:  получает n бит, начиная с p-й позиции */
unsigned getbits(unsigned x, int p, int n)
{
    return (x >> (p+1-n)) & ~(~0 << n);
}
\end{ShortCodePar} 

\noindent Выражение \verb|x >> (p+1-n)| сдвигает нужное нам поле к правому краю.
Константа \verb|~0| состоит только из единиц, и её сдвиг влево на \verb|n| бит
\verb|(~0 << n)| приведёт к тому, что правый край этой константы займут \verb|n|
нулевых разрядов. Ещё одна операция побитового отрицания, \verb|~(~0 << n)|,
позволяет получить справа \verb|n| единиц.

\paragraph{Упражнение 2.6.} Напишите функцию \verb|setbits(x,p,n,y)|,
возвращающую значение \verb|x|, в котором \verb|n| бит, начиная с \verb|p|-й
позиции, заменены на \verb|n| правых разрядов из \verb|y| (остальные биты не
изменяются).

\paragraph{Упражнение 2.7.} Напишите функцию \verb|invert(x,p,n)|, возвращающую
значение \verb|x| с инвертированными \verb|n| битами, начиная с позиции \verb|p|
(остальные биты не изменяются).
 
\paragraph{Упражнение 2.8.} Напишите функцию \verb|rightrot(x,n)|, которая
циклически сдвигает (<<вращает>>) вправо \verb|x| на \verb|n| разрядов.

\section{Операторы присваивания и выражения}

\index{выражение!присваивание}%
\index{операторы!присваивания}%
\index{оператор!присваивания \texttt{+=}}%
\index{присваивание!выражение}%
Выражение типа

\begin{ShortCodePar}
i = i + 2
\end{ShortCodePar}

\noindent в котором стоящая слева переменная повторяется и справа, можно
написать в сжатом виде:

\begin{ShortCodePar}
i += 2
\end{ShortCodePar}

\noindent Оператор \verb|+=| называется \emph{оператором присваивания}.

\index{оператор!присваивания \texttt{*=}}%
\index{оператор!присваивания \texttt{\slash=}}%
\index{оператор!присваивания \texttt{\%=}}%
\index{оператор!присваивания \texttt{+=}}%
\index{оператор!присваивания \texttt{\textminus=}}%
\index{оператор!присваивания \texttt{\textless}\texttt{\textless=}}%
\index{оператор!присваивания \texttt{\textgreater}\texttt{\textgreater=}}%
\index{оператор!присваивания \texttt{\&=}}%
\index{оператор!присваивания \texttt{\textasciicircum=}}%
\index{оператор!присваивания \texttt{"|=}}%
Большинству бинарных операторов (аналогичных \verb|+| и имеющих левый и правый
операнды) соответствуют операторы присваивания \textit{\Verb|op|}\verb|=|, где
\textit{\Verb|op|} -- один из операторов

\begin{ShortCodePar}
+   -   *   /   %   <<   >>   &   ^   |
\end{ShortCodePar}

\noindent Если \textit{выр}$_{1}$ и \textit{выр}$_{2}$ -- выражения, то запись

\begin{ShortCodeParWithCC}{\\\{\}}
\textit{выр}\textsubscript{1} \textit{op}= \textit{выр}\textsubscript{2}
\end{ShortCodeParWithCC}

\noindent эквивалентна записи

\begin{ShortCodeParWithCC}{\\\{\}}
\textit{выр}\textsubscript{1} = (\textit{выр}\textsubscript{1}) \textit{op}\
(\textit{выр}\textsubscript{2})
\end{ShortCodeParWithCC}

\noindent с той лишь разницей, что \textit{выр}$_{1}$ вычисляется только один
раз. Обратите внимание на скобки вокруг \textit{выр}$_{2}$: запись

\begin{ShortCodePar}
x *= y + 1
\end{ShortCodePar} 

\noindent эквивалентна записи

\begin{ShortCodePar}
x = x * (y + 1)
\end{ShortCodePar}

\noindent но не

\begin{ShortCodePar}
x = x * y + 1
\end{ShortCodePar}

\index{функция!bitcount@\texttt{bitcount}}%
В качестве примера приведём функцию \verb|bitcount|, подсчитывающую число
единичных битов в своём аргументе целого типа.

\begin{LongCodePar}
/* bitcount: подсчёт 1 в x */
int bitcount(unsigned x)
{
    int b;

    for (b = 0; x != 0; x >>= 1)
        if (x & 01)
            b++;
    return b;
}
\end{LongCodePar}

\noindent%
\index{unsigned@\texttt{unsigned}!тип}%
Независимо от машины, на которой будет работать эта программа, описание
аргумента \verb|x| как \verb|unsigned| гарантирует, что при правом сдвиге
освобождающиеся биты будут заполняться нулями, а не знаковым битом.

\index{программа!читаемость}%
Помимо краткости операторы присваивания обладают тем преимуществом, что они
более соответствуют тому, как человек мыслит. Мы говорим <<прибавить $2$ к
\verb|i|>> или <<увеличить \verb|i| на $2$>>, а не <<взять \verb|i|, добавить
$2$ и затем вернуть результат в \verb|i|>>, так что выражение \verb|i += 2|
лучше, чем \verb|i = i + 2|. Кроме того, в сложных выражениях вроде

\begin{ShortCodePar}
yyval[yypv[p3+p4] + yypv[p1+p2]] += 2
\end{ShortCodePar} 

\noindent благодаря оператору присваивания запись становится более лёгкой для
понимания, так как читателю при такой записи не потребуется старательно
сравнивать два длинных выражения или выяснять, почему они не совпадают.
\index{эффективность}%
Следует иметь в виду и то, что оператор присваивания может помочь компилятору
сгенерировать более эффективный код.

\index{инструкции!присваивания вложенные}%
\index{оператор!присваивания \texttt{=}}%
\index{присваивание!инструкция вложенная}%
Мы уже видели, что присваивание вырабатывает значение и может применяться внутри
выражения; во многих рядовых программах мы видим

\begin{ShortCodePar}
while ((c = getchar()) != EOF)
    ...
\end{ShortCodePar}

\noindent В выражениях встречаются и другие операторы присваивания (\verb|+=|,
\verb|-=| и т.д.), хотя и реже.

Типом и значением любого выражения присваивания являются тип и значение его
левого операнда после завершения присваивания.

\paragraph{Упражнение 2.9.} Применительно к числам, в представлении которых
использован дополнительный код, выражение \verb|x &= (x-1)| уничтожает самую
правую 1 в \verb|x|. Объясните, почему. Используйте это наблюдение при написании
более быстрого варианта функции \verb|bitcount|.

\section{Условные выражения}

\index{условное выражение}%
Инструкции

\begin{ShortCodePar}
if (a > b)
    z = a;
else
    z = b;
\end{ShortCodePar} 

\noindent пересылают в \verb|z| максимальное из двух значений, \verb|a| и
\verb|b|. \emph{Условное выражение}, написанное с помощью тернарного оператора
<<\verb|?:|>>, представляет собой другой способ записи этой и подобных ей
конструкций. В выражении

\begin{ShortCodeParWithCC}{\\\{\}}
\textit{выр}\textsubscript{1} ? \textit{выр}\textsubscript{2} :\
\textit{выр}\textsubscript{3}
\end{ShortCodeParWithCC}

\noindent первым вычисляется выражение \textit{выр}$_{1}$. Если его значение не
нуль (истина), то вычисляется выражение \textit{выр}$_{2}$, и значение этого
выражения становится значением всего условного выражения. В противном случае
вычисляется выражение \textit{выр}$_{3}$, и его значение становится значением
условного выражения. Следует отметить, что из выражений \textit{выр}$_{2}$ и
\textit{выр}$_{3}$ вычисляется только одно из них. Таким образом, чтобы
установить в \verb|z| наибольшее из \verb|a| и \verb|b|, можно написать

\begin{ShortCodePar}
z = (a > b) ? a : b;    /* z = max(a, b) */
\end{ShortCodePar} 

Следует заметить, что условное выражение и в самом деле является выражением, и
его можно использовать в любом месте, где допускается выражение. Если
\textit{выр}$_{2}$ и \textit{выр}$_{3}$ принадлежат разным типам, то тип
результата определяется правилами преобразования, о которых шла речь в этой
главе ранее. Например, если \verb|f| имеет тип \verb|float|, а \verb|n| -- тип
\verb|int|, то типом выражения

\begin{ShortCodePar}
(n > 0) ? f : n
\end{ShortCodePar}

\noindent будет \verb|float|, вне зависимости от того, положительно значение
\verb|n| или нет.

Заключать в скобки первое выражение в условном выражении не обязательно, так как
приоритет \verb|?:| очень низкий (более низкий приоритет имеет только
присваивание), однако мы рекомендуем всегда это делать, поскольку благодаря
обрамляющим скобкам условие в выражении лучше воспринимается.

Условное выражение часто позволяет сократить программу. В качестве примера
приведём цикл, обеспечивающий печать \verb|n| элементов массива по 10 на каждой
строке с одним пробелом между колонками; каждая строка цикла, включая последнюю,
заканчивается литерой новая-строка:

\begin{ShortCodePar}
for (i = 0; i < n; i++)
   printf("%6c%d", a[i], (i%10==9 || i==n-1) ? '\n' : ' ');
\end{ShortCodePar}

\noindent Литера новая-строка посылается после каждого десятого и после
\verb|n|-го элемента. За всеми другими элементами следует пробел. Эта программа
выглядит довольно замысловато, зато она более компактна, чем эквивалентная
программа с использованием \verb|if-else|. Вот ещё один пример:

{\setlength{\codeIndent}{\codeIndentBk-1em}
\begin{ShortCodePar}
printf("Вы имеете %d элемент%s.\n", n, (n%10==1 && n!=11) ? "" :
           ((n<10 || n>20) && n%10>=2 && n%10<=4) ? "а" : "ов");
\end{ShortCodePar}
\setlength{\codeIndent}{\codeIndentBk}}

\paragraph{Упражнение 2.10.} Напишите функцию \verb|lower|, которая переводит
большие буквы в малые, используя условное выражение (вместо \verb|if-else|).

\section{Приоритет и порядок вычислений}

\index{выражение!порядок вычисления}%
\index{вычисление, порядок}%
\index{оператор!приоритет}%
\index{операторы!ассоциативные}%
\index{порядок!вычислений}%
\index{приоритеты операторов}%
В табл.~\ref{tab:precedence} показаны приоритеты и порядок вычислений всех
операторов, включая и те, которые мы ещё не рассматривали. Операторы,
перечисленные на одной строке, имеют одинаковый приоритет; строки упорядочены по
убыванию приоритетов; так, например, \verb|*|, \verb|/| и \verb|%| имеют
одинаковый приоритет, который выше, чем приоритет бинарных \verb|+| и \verb|-|.
<<Оператор>> \verb|()| обозначает вызов функции. Операторы \verb|->| и \verb|.|
(точка) обеспечивают доступ к элементам структур; о них пойдёт речь в
гл.~\ref{chapt:structures}, там же будет рассмотрен и оператор \verb|sizeof|
(размер объекта). Операторы \verb|*| (адресация по указателю) и \verb|&|
(получение адреса объекта) обсуждаются в гл.~\ref{chapt:pointers_and_arrays}.
Оператор <<запятая>> будет рассмотрен в гл.~\ref{chapt:control_flow}.

Заметим, что приоритеты побитовых операторов \verb|&|, \verb|^| и \verb!|! ниже,
чем приоритет \verb|==| и \verb|!=|, из-за чего в побитовых проверках типа

\begin{ShortCodePar}
if ((x & MASK) == 0) ...
\end{ShortCodePar}

\noindent чтобы получить правильный результат, приходится использовать скобки.

Си подобно многим языкам не фиксирует порядок вычисления операндов оператора (за
исключением \verb|&&|, \verb!||!, \verb|?:| и <<\verb|,|>>). Например, в
инструкции вида

\begin{ShortCodePar}
x = f() + g();
\end{ShortCodePar}

\noindent%
\index{побочный эффект}%
\verb|f| может быть вычислена раньше \verb|g| или наоборот. Из этого
следует, что если одна из функций изменяет значение переменной, от которой
зависит другая функция, то помещаемый в \verb|x| результат может зависеть от
порядка вычислений. Чтобы обеспечить нужную последовательность вычислений,
промежуточные результаты можно запоминать во временных переменных.

Порядок вычисления аргументов функции также не определён, поэтому на разных
компиляторах

\begin{ShortCodePar}
printf("%d %d\n", ++n, power(2, n));    /* НЕВЕРНО */
\end{ShortCodePar}

\begin{table}[t]
\centering
\captionsetup{name=ТАБЛИЦА,labelsep=period,justification=centering}
\renewcommand\thetable{2.1}
\caption{ПРИОРИТЕТЫ И ПОРЯДОК ВЫЧИСЛЕНИЙ ОПЕРАТОРОВ}
\label{tab:precedence}
\index{вычисление, порядок}%
\index{порядок!вычислений}%
\index{приоритеты операторов}%
\index{таблица!операторов}%
{%
\SetLenVarWithWidth{\colAlen}{\Verb!= += -= *= /= \%= \&= \^= |= <<= >>=!}%
\SetLenVarWithWidth{\colBlen}{ВЫПОЛНЯЮТСЯ}%
\begin{tabular*}{\colAlen+\colBlen+4\tabcolsep}{p{\colAlen}|p{\colBlen}}
\hline\hline
\multicolumn{1}{c|}{\rule{0pt}{3ex}ОПЕРАТОРЫ\rule[-1.5ex]{0pt}{0pt}} &
\multicolumn{1}{|c}{ВЫПОЛНЯЮТСЯ} \\
\hline
\rule{0pt}{3ex}\verb|()  []  ->  .| &\multicolumn{1}{|c}{\Verb|слева направо|}
\\
\verb|! ~ ++ -- + - * & (|\textit{\Verb|тип|}\verb|) sizeof|
&\multicolumn{1}{|c}{\Verb|справа налево|} \\
\verb|*   /   %| &\multicolumn{1}{|c}{\Verb|слева направо|} \\
\verb|+   -| &\multicolumn{1}{|c}{\Verb|слева направо|} \\
\verb|<<  >>| &\multicolumn{1}{|c}{\Verb|слева направо|} \\
\verb|<   <=   >   >=| &\multicolumn{1}{|c}{\Verb|слева направо|} \\
\verb|==  !=| &\multicolumn{1}{|c}{\Verb|слева направо|} \\
\verb|&| &\multicolumn{1}{|c}{\Verb|слева направо|} \\
\verb|^| &\multicolumn{1}{|c}{\Verb|слева направо|} \\
\verb+|+ &\multicolumn{1}{|c}{\Verb|слева направо|} \\
\verb|&&| &\multicolumn{1}{|c}{\Verb|слева направо|} \\
\verb+||+ &\multicolumn{1}{|c}{\Verb|слева направо|} \\
\verb|?:| &\multicolumn{1}{|c}{\Verb|справа налево|} \\
\verb!= += -= *= /= %= &= ^= |= <<= >>=!
&\multicolumn{1}{|c}{\Verb|справа налево|} \\
\rule[-1.5ex]{0pt}{0pt}\verb|,| &\multicolumn{1}{|c}{\Verb|слева направо|} \\
\hline
\multicolumn{2}{c}{\small \rule{0pt}{3ex} Унарные операторы \Verb|+|, \Verb|-| и
\Verb|*| имеют более высокий}\\
\multicolumn{2}{c}{\small приоритет, чем те же операторы в бинарном варианте}
\end{tabular*}}
\end{table}

\noindent может давать несовпадающие результаты. Результат вызова функции
зависит от того, когда компилятор сгенерирует команды увеличения \verb|n| до
или после обращения к \verb|power|. Чтобы обезопасить себя от возможного
побочного эффекта, достаточно написать

\begin{ShortCodePar}
++n;
printf("%d %d\n", n, power(2, n));
\end{ShortCodePar}

\index{побочный эффект}%
Обращения к функциям, вложенные присваивания, инкрементные и декрементные
операторы дают <<побочный эффект>>, проявляющийся в том, что при вычислении
выражения значения некоторых переменных изменяются. В любом выражении с побочным
эффектом может быть скрыта трудно просматриваемая зависимость результата
выражения от порядка изменения значений переменных, входящих в выражение. В
такой, например, типично неприятной ситуации --

\begin{ShortCodePar}
a[i] = i++;
\end{ShortCodePar}

\noindent возникает вопрос: массив \verb|a| индексируется старым или изменённым
значением \verb|i|? Компиляторы могут по-разному генерировать программу, что
проявится в интерпретации данной записи. Стандарт сознательно устроен так, что
большинство подобных вопросов оставлено на усмотрение компиляторов, так как
лучший порядок вычислений определяется архитектурой машины. Стандартом только
гарантируется, что все побочные эффекты при вычислении аргументов проявятся
перед входом в функцию. Правда, в примере с \verb|printf| это нам не поможет.

Мораль такова: писать программы, которые зависят от порядка вычислений, --
плохая практика, какой бы язык вы ни использовали. Естественно, надо знать, чего
следует избегать, но если вы не знаете, \emph{как} образуются побочные эффекты
на вашей машине, то лучше и не рассчитывать на особенности реализации.
