--PAGE_BREAK-- 2.2 Алфавит, базовые типы и описание данных. Алфавит языка включает практически все символы, имеющиеся на стандартной клавиатуре ПЭВМ:
— латинские буквы A...Z, a...z;
— цифры 0...9;
— знаки операций и разделители:
{ } [ ] ( )., -> & * + — ~! / %?:; = | # ^
Некоторые операции обозначаются комбинациями символов, значения символов операций в ряде случаев зависят от контекста, в котором они употреблены.
Базовые (предопределенные) типы данных объединены в две группы: данные целого типа и данные с плавающей точкой (вещественные).
Данные целого типа могут быть обычными целыми со знаком (signed) и целыми без знака (unsigned). По числу разрядов, используемых для представления данного (диапазону значений) различают обычные целые (int), короткие целые (short int) и длинные целые (long int ). Символьные данные (char) также рассматриваются как целые и могут быть со знаком и без знака.
Константы целого типа записываются как последовательности десятичных цифр, тип константы зависит от числа цифр в записи константы и может быть уточнен добавлением в конце константы букв L или l (тип long), U или u (тип unsigned) или их сочетания:
321 — константа типа int,
5326u — константа типа unsigned int,
45637778 — константа типа long int,
2746L — константа типа long int.
Целые константы могут записываться в восьмеричной системе счисления, в этом случае первой цифрой должна быть цифра 0, число может содержать только цифры 0… 7:
0777 — константа типа int,
0453377 — константа типа long.
Целые константы можно записывать и в шестнадцатеричной системе счисления, в этом случае запись константы начинается с символов 0x или 0X:
0x45F — константа типа int,
0xFFFFFFFF — константа типа unsigned long.
Константы типа char всегда заключаются в одиночные кавычки, значение константы задается либо знаком из используемого набора символов, либо целой константой, которой предшествует обратная косая черта: 'A', '\33', '\042', '\x1B'. Имеется также ряд специальных символов, которые могут указываться в качестве значений константы типа char:
'\n' — новая строка,
'\t' — горизонтальная табуляция,
'\v' — вертикальная табуляция,
'\r' — перевод каретки,
'\f' — перевод страницы,
'\a' — звуковой сигнал,
'\'' — одиночная кавычка (апостроф),
'\"' — двойная кавычка,
'\\' — обратная косая черта.
Вещественные числа могут быть значениями одного из трех типов: float, double, long double. Диапазон значений каждого из этих типов зависит от используемых ЭВМ и компилятора. Константы вещественных типов могут записываться в естественной или экспоненциальной формах и по умолчанию имеют тип double, например, 15.31, 1.43E-3, 2345.1e4. При необходимости тип константы можно уточнить, записав в конце суффикс f или F для типа float, суффикс l или L для типа long double.
Внешнее определение, объявляющее переменные, состоит из необязательного спецификатора класса памяти, спецификаторов типа и списка так называемых деклараторов-инициализаторов, каждый из которых объявляет идентификатор одной переменной и, возможно, значение, присваиваемое переменной при ее объявлении. Внешнее определение заканчивается точкой с запятой:
Текст, записанный в этих примерах после знаков //, является комментарием и служит только для документирования программы. Такой комментарий может занимать только одну строку текста и допускается в текстах программ на Си++. Комментарий, занимающий несколько строк, заключается в специальные скобки /* и */.
В качестве спецификаторов класса памяти во внешнем определении может указываться одно из ключевых слов extern, static или typedef, Спецификатор extern означает, что объявляемый объект принадлежит другому программному файлу, а здесь дается информация о его имени и типе и не должно присутствовать инициализирующее выражение. Спецификатор static ограничивает область действия объявляемого имени данным файлом или блоком, если объявление содержится в блоке.
Если объявление данного содержится внутри тела функции (локальное объявление), то можно указывать спецификаторы класса памяти register или auto. Спецификатор register носит рекомендательный характер, компилятор пытается разместить данное этот класса в регистре процессора, если в данный момент имеются свободные регистры. Спецификатор auto принимается по умолчанию и поэтому явно не указывается, он означает, что данное класса auto должно размещаться в программном стеке при вызове функции.
Спецификатор typedef служит для присвоения имени описываемому типу данного и будет рассмотрен подробнее в следующем параграфе.
Наряду с показанными выше константами-литералами, значения которых определяются их представлением в программе, в Си и Си++ предусмотрены константы, которым присваиваются собственные имена — именованные константы. В описании именованной константы присутствует описатель const, например,
Переменной, идентификатор которой объявлен с описателем const, нельзя присвоить иное значение, чем было установлено при объявлении идентификатора. Инициализирующее значение при объявлении константы является обязательным.
Наряду с базовыми целыми и вещественными типами различных размеров в программе могут объявляться и использоваться данные типов, определяемых программистом: указатели, ссылки, агрегаты данных и данные перечислимого типа.
Перечислимый тип применяется для данных целого типа, которые могут принимать ограниченный набор значений. Каждому значению соответствует собственное имя-идентификатор и целое число, значение этого имени. Объявление перечислимого типа строится по схеме:
Здесь идентификатор задает имя перечислимого типа, список перечисления состоит из перечислителей, разделенных запятыми. Каждый перечислитель задается идентификатором и, возможно, целым значением типа char или int, например, Если значение перечислителя не задано, первый из них получает значение 0, а каждый следующий — значение, большее на 1. Вообще любой перечислитель по умолчанию имеет значение на 1 больше предыдущего. В Си/Си++ принято записывать идентификаторы перечислителей прописными буквами. Имена перечислителей используется либо как именованные константы либо для присвапивания переменным перечислимого типа. В Си/Си++ для ссылок на переменную того или иного типа служат указатели. Указатель — это тип данного, значением которого является адрес другого данного. При объявлении указателя перед идентификатором записывается знак *. Указатель может инициализироваться адресом данного, для получения адреса служит операция & (амперсенд):
Для указателей определены операции сравнения, сложения указателя с целым числом, вычитание двух указателей, а также операция индексирования (операция []).
Для обращения к переменной по указателю выполняется операция разыменования, обозначаемая знаком * (звездочка), например, *py = 7.5;.
При объявлении указателя может использоваться описатель const, например,
Кроме обычных переменных и указателей в Си++ имеется тип «ссылка на переменную», задающий для переменной дополнительное имя (псевдоним). Внутреннее представление ссылки такое же, как указателя, т.е. в виде адреса переменной, но обращение к переменной по ссылке записывается в той же форме, что и обращение по основному имени. Переменная типа ссылки всегда инициализируется заданием имени переменной, к которой относится ссылка. При объявлении ссылки за именем типа записывается знак & (амперсенд):
При таком описании операторы aii = 5; и ii = 5; эквивалентны.
Из переменных любого типа могут образовываться массивы. При объявлении массива в деклараторе-инициализаторе за идентификатором массива задается число элементов массива в квадратных скобках:
Индексы элементов массива всегда начинаются с 0, индекс последнего элемента на единицу меньше числа элементов в массиве. Массив может инициализироваться списком значений в фигурных скобках:
При наличии списка инициализации, охватывающего все элементы массива, можно не указывать число элементов массива, оно будет определено компилятором:
Массивы с размерностью 2 и более рассматриваются как массивы массивов и для каждого измерения указывается число элементов:
Массивы типа char могут инициализироваться строковым литералом. Строковый литерал — это последовательность любых символов, кроме кавычек и обратной косой черты, заключенная в кавычки. Если строковый литерал не умещается на одной строке, его можно прервать символом "\" и продолжить с начала следующей строки. В стандарте C++ предусмотрена и другая возможность записи длинных литералов в виде нескольких записанных подряд строковых литералов. Если между строковыми литералами нет символов, отличных от пробелов, такие литералы сливаются компилятором в один.
При размещении в памяти в конце строкового литерала добавляется символ '\0', т.е. нулевой байт. Строковый литерал может применяться и для инициализации указателя на тип char:
Имя массива в Си/Си++ является указателем-константой, ссылающимся на первый элемент массива, имеющий индекс, равный нулю. Для обращения к элементу массива указывается идентификатор массива и индекс элемента в круглых скобках, например, c[2], aa[0][1].
2.3 Структуры и объединения Наряду с массивами в Си/Си++ имеются агрегаты данных типа структур и объединений. Тип структуры представляет собой упорядоченную совокупность данных различных типов, к которой можно обращаться как к единому данному. Описание структурного типа строится по схеме:
struct идентификатор
{ деклараторы членов } деклараторы_инициализаторы;
Такое объявление выполняет две функции, во-первых объявляется структурный тип, во-вторых объявляются переменные этого типа.
Идентификатор после ключевого слова struct является именем структурного типа. Имя типа может отсутствовать, тогда тип будет безымянный и в других частях программы нельзя будет объявлять данные этого типа. Деклараторы_инициализаторы объявляют конкретные переменные структурного типа, т.е. данные описанного типа, указатели на этот тип и массивы данных. Деклараторы_инициализаторы могут отсутствовать, в этом случае объявление описывает только тип структуры.
Структура, описывающая точку на плоскости, может быть определена так:
Члены (компоненты) структуры описываются аналогично данным соответствующего типа и могут быть скалярными данными, указателями, массивами или данными другого структурного типа. Например, для описания структурного типа «прямоугольник со сторонами, параллельными осям координат» можно предложить несколько вариантов:
Поскольку при описании членов структуры должны использоваться только ранее определенные имена типов, предусмотрен вариант предварительного объявления структуры, задающий только имя структурного типа. Например, чтобы описать элемент двоичного дерева, содержащий указатели на левую и правую ветви дерева и указатель на некоторую структуру типа Value, содержащую значение данного в узле, можно поступить так:
Членами структур могут быть так называемые битовые поля, когда в поле памяти переменной целого типа (int или unsigned int) размещается несколько целых данных меньшей длины. Пусть, например, в некоторой програме синтаксического разбора описание лексемы содержит тип лексемы (до шести значений) и порядковый номер лексемы в таблице соответствующего типа (до 2000 значениий). Для представления значения типа лексемы достаточно трех двоичных разрядов (трех бит), а для представления чисел от 0 до 2000 — 11 двоичных разрядов (11 бит). Описание структуры, содержащей сведения о лексеме может выглядеть так:
Двоеточие с целым числом после имени члена структуры указывает, что это битовое поле, а целое число задает размер поля в битах.
Объединение можно определить как структуру, все компоненты которой размещаются в памяти с одного и того же адреса. Таким образом, объединение в каждый момент времени содержит один из возможных вариантов значений. Для размещения объединения в памяти выделяется участок, достаточный для размещения члена объединения самого большого размера. Применение объединения также позволяет обращаться к одному и тому же полю памяти по разным именам и интерпретировать как значения разных типов.
Описание объединения строится по той же схеме, что и описание структуры, но вместо ключевого слова struct используется слово union, например, объединение uword позволяет интерпретировать поле памяти либо как unsigned int, либо как массив из двух элементов типа unsigned char.
Описания типов, объявляемых программистом, в том числе структур и объединений могут быть достаточно большими, поэтому в Си/Си++ предусмотрена возможность присваивания типам собственных имен (синонимов), достигая при этом повышения наглядности программных текстов. Синоним имени типа вводится с ключевым словом typedef и строится как обычное объявление, но идентификаторы в деклараторах в этом случае интерпретируются как синонимы описанных типов. Синонимы имен типов принято записывать прописными буквами, чтобы отличать их от идентификаторов переменных. Ниже приведено несколько примеров объявления синонимов имен типов.
После таких объявлений синоним имени может использоваться как спецификатор типа:
Приведенное выше описание структур и объединений в основном соответствует их построению в языке Си. В Си++ структуры и объединения являются частными случаями объектных типов данных. Дополнительные сведения об этом будут приведены при рассмотрении объектно-ориентированных средств Си++.
2.4 Операции и выражения Несмотря на ограниченный набор базовых типов данных (целые и вещественные арифметические данные и строковые литералы) в языке Си++ определен обширный набор операций над данными, часть из которых непосредственно соответствует машинным командам. Как и во всех языках программирования, операции служат для построения выражений. Выражение представляет собой последовательность операндов и знаков операций и служит для вычисления некоторого значения.
В качестве операндов в выражении выступают идентификаторы переменных, константы, и строковые литералы, являющиеся первичными выражениями. Выражение, заключенное в круглые скобки, также рассматривается как первичное. Каждая операция предполагает использование определенных типов операндов (целых, вещественных, указателей). Операция присваивания в Си++ также является выражением, в связи с этим различаются операнды, которым можно присвоить новое значение и операнды, значение которых не может меняться. Чтобы операнду можно было присвоить значение, ему должна соответствовать область памяти и компилятору должен быть известен адрес этой памяти. Такие операнды называют L-выражениями (от английского left -левый), так как они могут быть записаны в левой части оператора присваивания.
продолжение
--PAGE_BREAK--Результат вычисления выражения зависит от приоритетов операций. В Си++ сложная система приоритетов операций, включающая 16 уровней. В таблице 2.1 приведен перечень операций Си++ с указанием их приоритетов, назначения и схемы записи.
Таблица 2.1 Приоритет
Знак операции
Назначение
Схема
1
::
Доступ к глобальному имени или имени из другой области
:: идентификатор (глобальный)
имя области:: имя_члена_структуры
1
->
Обращение к члену структуры по указателю на структуру
указатель -> имя_члена_структуры
1
.
Обращение к члену структуры по имени структуры
имя_структуры. имя_члена_структуры
1
[ ]
Обращение к элементу массива
указатель [ индекс ]
1
( )
Преобразование типа данного
имя_типа (выражение ) или (тип) выражение
1
( )
Вызов функции
функция(аргументы)
2
++
Автоувеличение
++ L-значение или
L-значение++
2
—
Автоуменьшение
— L-значение или
L-значение--
2
~
Битовое инвертирование
~ целое_выражение
2
!
Логическое отрицание
! выражение
2
—
Одноместный минус
— выражение
2
+
Одноместный плюс
+ выражение
2
&
Получение адреса
& L-значение
2
*
Разыменование указателя
* указатель
2
new
Выделение динамической памяти
new тип данного
2
delete
Освобождение памяти
delete указатель
2
delete []
Освобождение памяти для массива
delete [] указатель
2
sizeof
Размер данного
sizeof выражение
2
Размер типа данного
sizeof (имя типа )
3
*
Умножение
выражение * выражение
3
/
Деление
выражение / выражение
3
%
Остаток от деления нацело
выражение % выражение
4
->*
Обращение к члену структуры по указателю
указатель_на_структуру ->* имя_члена_структуры-указателя
4
.*
Обращение к члену структуры по имени структуры
имя_структуры .*
имя_члена_структуры-указателя
5
+
Сложение
выражение + выражение
5
—
Вычитание
выражение — выражение
6
Сдвиг влево
целое_выражение
6
>>
Сдвиг вправо
целое_выражение >> целое_выражение
7
Меньше
выражение
7
Меньше или равно
выражение
7
>
Больше
выражение > выражение
7
>=
Больше или равно
выражение >= выражение
8
==
Равно
выражение == выражение
8
!=
Не равно
выражение != выражение
9
&
Поразрядная конъюнкция
выражение & выражение
10
^
Отрицание равнозначности
выражение ^ выражение
11
|
Поразрядная дизъюнкция
выражение | выражение
12
&&
Логическое «И»
выражение && выражение
13
| |
Логическое «ИЛИ»
выражение | | выражение
14
?:
Условное выражение
выражение? выражение1: выражение2
15
=
Простое присваивание
выражение = выражение
15
@=
Составное присваивание, знак @ — один из знаков операций * / % + — > & ^ |
выражение @= выражение
16
,
Операция следования
выражение, выражение
Рассмотрим особенности применения основных из перечисленных выше операций.
Операция ": :" (два двоеточия) применяется для уточнения имени объекта программы в случае, когда в этом месте программы известны два одинаковом имени, например, когда одно имя объявлено глобально, а другое в теле функции. Если имени предшествуют два двоеточия, то это глобальное имя.
Для обращения к членам структуры или объединения можно воспользоваться либо именем структурного данного, либо указателем на структурное данное. В первом случае полное имя члена структуры состоит из имени самой структуры и имени члена структуры, разделенных точкой. Во втором случае за именем указателя на структуру ставится знак -> (стрелка), а за ним имя члена структуры. Пусть в программе объявлен структурный тип AnyStruct, содержащий компоненту с именем member типа int и объявлены
AnyStruct s1; // Данное s1 типа AnyStruct
AnyStruct *ps1 = &s1; // Указатель на данное типа AnyStruct
Тогда к члену структуры member из s1 можно обратиться как к s1.member или как ps1->member.
Поскольку членом структуры может быть указатель, в Си++ имеются специальные операции разыменования такого указателя, операции .* и ->. Пусть одним из членов структуры AnyStruct является указатель pp1 на данное типа int. Тогда выражения s1.*pp1 и ps1->*pp1 обеспечат доступ к значению данного, на которое указывает pp1 из s1.
Выше отмечалось, что имя массива в Си/Си++ интерпретируется как указатель-константа на первый элемент массива. Для разыменования указателя, т.е. для доступа к данному по указателю на это данное служит операция * (звездочка). Следовательно, если в программе объявлен массив
int Array1 [ 10 ];
то выражение *Array1=0 служит для присвоения нулевого значения первому элементу массива. Чтобы обратиться к произвольному элементу массива, нужно указать индекс элемента, например, Array1 [3]. Это выражение эквивалентно выражению *(Array1 + 3), т.е. требуется сначала увеличить указатель Array1 на 3 единицы, а затем разыменовать полученный указатель. При сложении указателя на объект некоторого типа T с целым числом N значение указателя увеличивается на N, умноженное на длину данного типа T. Отметим, что индекс можно задавать не только для имен массивов, но и для любого типа указателя, кроме указателя на тип void: int *pint = &Array[ 4 ]; pint [ 2 ] =1;
В этом примере указатель pint инициализирован адресом пятого элемента массива Array, а затем седьмому элементу этого массива присвоено значение 1.
В качестве индекса может задаваться любое выражение со значением целого типа.
Поскольку Си++ является типизированным языком, в нем определены явные и неявные преобразования типов данных. Неявные преобразования выполняются при двуместных арифметических операциях и операции присваивания и называются стандартными арифметическими преобразованиями. Эти преобразования выполняются в следующей последовательности:
— если один операнд имеет тип long double, другой операнд преобразуется в тип long double;
— иначе, если один операнд имеет тип double, другой операнд преобразуется в тип double;
— иначе, если один операнд имеет тип float, другой операнд преобразуется в тип float;
— иначе, если один операнд имеет тип unsigned long int, другой операнд преобразуется в тип unsigned long int;
— иначе, если один операнд имеет тип long int, >другой операнд преобразуется в тип long int;
— иначе, выполняются стандартные преобразования для целых, при этом типы char, short int и битовые поля типа int преобразуются в тип int, затем, если один операнд имеет больший размер (больший диапазон значений), чем другой операнд, то второй операнд преобразуется к типу операнда большего размера;
— в остальных случаях операнды имеют тип int.
Явное преобразование типов может быть задано в двух формах. Первая форма совместима с Си, в ней за именем типа в круглых скобках записывается преобразуемое значение, которое может быть первичным выражением или выражением с одноместной операцией. Имя типа в этом случае может быть представлено последовательностью описателей, например, (long int * ) pp определеяет преобразование некоторого данного pp в тип указателя на long int. Вторая форма преобразования типа записывается как вызов функции, при этом имя типа должно задаваться идентификатором, например, int (x ). Следует отметить, что результат явного преобразования не является L-значением.
Операции автоувеличения и автоуменьшения ( ++ и — ) могут быть префиксными и постфиксными и вызывают увеличение (уменьшение) своего операнда на единицу, т.е. выражение ++x эквивалентно x = x +1, а --x эквивалентно x = x — 1. Префиксная операция выполняется до того, как ее операнд будет использован в вычислении выражения, а постфиксная операция выполняется после того, как ее операнд будет использован в выражении, например, в результате вычисления выражения
++x * 2 + y-- *3
переменная x сначала увеличивается на 1, а затем умножается на 2, переменная y сначала умножается на 3, затем уменьшается на 1. Если перед вычислением этого выражения x и y были равны 1, то результат выражения будет равен 5, кроме того переменная x получит значение 2, а переменная y — значение 0. Таким образом, операции автоувеличения и автоуменьшения всегда дают побочный эффект, изменяют значения своих операндов. Операнды этих операций должны быть L-значениями.
Операция ~ (тильда) применяется только к целому значению и заменяет все биты своего операнда со значением 0 на 1, а биты со значением 1 на 0.
Логическое отрицание (операция !) возвращает значение 0 целого типа, если операнд не равен нулю, или значение 1, если операнд равен нулю.
Операции «одноместный +» и «одноместный -» имеют обычный математический смысл, знак + не изменяет значения операнда, знак — меняет знак операнда на противоположный.
Для получения адреса операнда, являющегося L-значением, применяется операция & (амперсанд). Результатом этой операции будет указатель на соответствующий тип данного. Разыменование указателя, т.е. получение значения данного по указателю на него обеспечивается операцией * (звездочка). Результат операции разыменования является L-значением.
В Си++ определены операции размещения данных в динамической памяти и удаления динамических данных из памяти.
Операция new требует в качестве операнда имени типа и предназначена для размещения данного указанного типа в динамической памяти, результатом операции будет указатель на данное. При невозможности выделить память операция new возвращает значение NULL — предопределенную константу, имеющую нулевое значение практически во всех компиляторах Си и Си++. Память, выделяемую операцией new, можно инициализировать, указав за именем типа скалярного данного начальное значение в круглых скобках, задание начальных значений для агрегатов данных будет рассмотрено позже. Примеры применения операции new:
Данное, размещенное в динамической памяти операцией new, удаляется из памяти операцией delete с операндом-указателем, значение которого получено операцией new, например,
Операция delete только освобождает динамическую память, но не изменяет значение указателя-операнда. Программист должен помнить, что после освобождения памяти использовать этот указатель для обращения к данному нельзя.
Размер данного или типа данного в байтах можно получить по операции sizeof. Операнд может быть любого типа, кроме типа функции и битового поля. Если операндом является имя типа, оно должно заключаться в скобки. Возвращаемое значение имеет предопределенный тип size_t, это целый тип, размер которого определяется реализацией компилятора, обычно типу size_t соответствует unsigned int. Размер массива равен числу байт, занимаемых массивом в памяти, размер строкового литерала — это число знаков в литерале +1, т.е. завершающий нулевой байт учитывается при определении длины литерала. Значение, возвращаемое sizeof является константой.
Двуместные арифметические операции умножения ( * ), деления ( / ), получения остатка от деления нацело ( % ), сложения ( + ) и вычитания ( — ) имеют обычный смысл и обычный относительный приоритет. Если операнды арифметической операции имеют разные типы, предварительно выполняются стандартные арифметические преобразования и тип результата операции определяется общим типом операндов после стандартных преобразований. Следовательно, выражение 7/2 будет иметь значение 3 типа int, так как оба опернда имеют тип int, а выражение 7.0/2 даст результат 3.5 типа double, поскольку этот тип имеет первый операнд.
Операции отношения двух выражений (, >=) требуют операндов арифметического типа или же оба операнда должны быть указателями на одинаковый тип. В случае операндов арифметического типа вычисляются значения операндов, выполняются стандартные арифметические преобразования и возвращается 1 типа int, если отношение выполняется (истинно), или 0, если отношение не выполняется (ложно). Когда сравниваются два указателя, результат зависит от относительного размещения в памяти объектов, на которые ссылаются указатели. Операции сравнения ( == и != ) выполняются аналогичным образом, но имеют меньший приоритет.
Выражения отношений могут соединяться логическими связками && (конъюнкция, логическое умножение) и | | (дизъюнкция, логическое сложение). В общем случае операндами логических связок могут быть любые скалярные значения и операция && дает реззультат, равный 1 типа int, если оба операнда имеют ненулевые значения, а операция | | дает результат, равный 0, если значения обоих операндов нулевые. Применяется сокращенная форма вычисления значения логических связок, если в операции && первый операнд равен нулю, то второй операнд не вычисляется и возвращается 0, если в операции | | первый операнд не равен нулю, то второй операнд не вычисляется и возвращается значение 1.
Как уже отмечалось, присваивание, обозначаемое знаком = в Си/Си++ рассматривается как операция и возвращает значение, которое было присвоено левому операнду. Операция присваивания вычисляется справа налево, т.е. сначала вычисляется присваиваемое значение, затем выполняется присваивание. Это позволяет записывать выражения вида x = y = z = 1 для установки одинаковых значений нескольким переменным. Можно, хотя это и снижает наглядность программы, строить и выражения с побочным эффектом вида (x = 2) * (y = 3) + (z = 4 ). Результатом этого выражения будет 24, но одновременно переменные x, y и z получат новые значения.
Кроме простого присваивания имеется набор составных операций присваивания, в которых присваивание совмещается с указанной двуместной операцией. Запись x += y эквивалентна выражению x = x + y.
Для целых операндов определены операции сдвига влево и вправо. При выполнении операции e1 > e2 ) если e1 имеет тип unsigned, освобождающиеся левые разряды заполняются нулями, а при e1 типа signed в освобождающихся левых разрядах повторяется знаковый разряд.
Над целыми операндами допустимы операции поразрядного логического умножения, логического сложения и исключающего или (отрицания равнозначности). В этих операциях операнды рассматриваются как последовательности битов и операция выполняется над каждой парой соответствующих разрядов из обоих операндов. Например, результатом выражения ( x >> ( p — n +1)) & ( ~(~0
продолжение
--PAGE_BREAK--