Арифметические и поразрядные операции в языке Си. Сокращенная форма записи операций. Условные выражения.
Над целочисленными данными (константами и переменными) в языках C, C++ можно выполнять обычные арифметические операции – сложение (x+y), вычитание (z-5), умножение (x1*x3) и деление (y/w). В отличие от языка Pascal здесь деление целочисленных операндов дает целочисленный результат. Например, 5/2=2. Для получения остатка от деления в C, C++ используется операция %, например, 5%2=1.
Целочисленные данные можно подвергать операции сдвига как влево (знак операции – <<), так и вправо (знак операции – >>) на заданное количество двоичных разрядов:
y=x<<3; // сдвиг влево на три двоичные разряда
z=y>>5; // сдвиг вправо на пять двоичных разрядов
Операция сдвига вправо работает по-разному для целых чисел со знаком и целых чисел без знака. Внимательно посмотрите на результат работы следующей программы:
#include <stdio.h>
#include <conio.h>
int main()
{
int x=5, y=-5;
unsigned z=0xFFFFFFFB;
printf("x=%x y=%x z=%x",x,y,z);
printf("\nx<<2=%x x>>2=%x",x<<2,x>>2);
printf("\ny<<2=%x y>>2=%x",y<<2,y>>2);
printf("\nz<<2=%x z>>2=%x",z<<2,z>>2);
getch();
return 0;
}
//=== Результат работы ===
x=5 y=fffffffb z=fffffffb
x<<2=14 x>>2=1
y<<2=ffffffec y>>2=fffffffe
z<<2=ffffffec z>>2=3ffffffe
Дело в том, что для чисел со знаком операция сдвига на n разрядов эквивалентна умножению на 2n при сдвиге влево или делению на 2n при сдвиге вправо. Поэтому для отрицательного операнда результат сдвига должен остаться отрицательным. С этой целью при сдвиге вправо производится размножение знакового разряда.
Над одноименными двоичными разрядами целочисленных операндов могут выполняться логические операции – логическое сложение (символ операции '|'), логическое умножение (символ операции '&'), исключающее ИЛИ (символ операции '^') и инвертирование (символ операции '~'). Приведенная ниже программа иллюстрирует выполнение указанных операций над переменными x=5 (двоичный код 00…0101) и y=7 (двоичный код 00…0111).
#include <stdio.h>
#include <conio.h>
int main()
{
int x=5, y=7;
printf("x=%x y=%x",x,y);
printf("\nx|y=%x x&y=%x",x|y,x&y);
printf("\nx^y=%x ~x=%x",x^y,~x);
getch();
return 0;
}
//=== Результат работы ===
x=5 y=7
x|y=7 x&y=5
x^y=2 ~x=fffffffa
Специальные формы оператора присваивания
Следующая группа операторов присваивания обязана своим происхождением формату машинных команд в двухадресных машинах:
COD A1,A2
Здесь COD – код машинной операции;
A1,A2 – адреса ячеек оперативной памяти и/или арифметических регистров.
Результат выполнения такой операции над содержимым A1 и A2 записывается по адресу A1 (A1=A1ÄA2). По аналогии с такой записью в языках C, C++ появилась следующая синтаксическая конструкция:
v Ä= exp; //вместо v = v Ä exp;
Здесь символ Ä обозначает один из следующих знаков двухместных операций:
+,-,*,/,%,<<,>>,&,|,^
Например:
x += 2; //вместо x=x+2;
z /= 1.5; //вместо z=z/1.5;
Довольно экзотически выглядит оператор присваивания, в правой части которого через запятую задана последовательность некоторых действий. Например:
x=(y=sin(a+b),z=cos(a-b),max(y,z));
Действия в скобках выполняются слева направо, т.е. сначала будет вычислено значение sin(a+b), которое занесут в переменную y, затем будет вычислено значение переменной z. Окончательным результатом скобки, которое будет присвоено переменной x, станет вычисление значения функции max(y,z).
Условный оператор
С помощью условного оператора в программе можно создать две альтернативные цепочки операторов, выполнение каждой из которых происходит в зависимости от истинности или ложности заданного условия:
if(условие) {S1; S2;...} [else {Q1;Q2;...}]
Если условие, указанное в круглых скобках истинно, то выполняется цепочка операторов S1, S2,… . В противном случае выполняется цепочка операторов Q1,Q2,… . Альтернативная ветвь вместе со служебным словом else может отсутствовать. И тогда речь идет о выполнении или обходе цепочки операторов S1,S2,… .
Простейшие условия задаются в виде проверки соотношения двух однотипных выражений:
if(a>b) cout<<a; else cout<<b;
if(x>=0) y=sqrt(x);
Напомним, что операции отношения в языках C, C++ обозначаются следующими символами и их комбинациями:
== | равно | != | не равно | > | больше |
>= | больше или равно | < | меньше | <= | меньше или равно |
Более сложные условия могут составляться из элементарных соотношений с помощью логических операций "ИЛИ" (||), "И" (&&), "НЕ" (!). Например, проверка принадлежности x диапазону [a,b] выглядит следующим образом:
if(a<=x && x<=b) ...
В качестве логического условия иногда можно встретить в круглых скобках обычное арифметическое выражение:
if(a)...
В языке C логические переменные отсутствуют. Вместо этого действует соглашение о том, что ложь эквивалентна нулевому значению числового выражения, а истина – не нулевому значению. Поэтому приведенная выше проверка эквивалентна соотношению:
if(a != 0)...