Изучив в течение 15 предыдущих уроков очень многое из языка C, а также попрактиковавшись изрядно с данным языком в наших учебных проектах, мы поняли, что для того, чтобы переменная получила новое значение, его надо ей как-то присвоить. Для этого мы использовали оператор присваивания =.
Оказывается, что есть ещё некоторые операторы, представляющие из себя вышеуказанный оператор присваивания в комбинации с другими операторами, также являющиеся операторами присваивания. Также существует возможность использовать операции присваивания в выражениях. Поэтому было принято решение посвятить этому отдельный урок. Думаю, что он будет небольшим, но весьма нужным.
Начнём с обычной базовой операции присваивания, которая обозначается вот так
=
Данный оператор является бинарным и операция с помощью него происходит над двумя операндами, которые находятся справа и слева оператора. Справа обычно выражение (может быть константа, которая, в принципе, тоже является выражением), а слева — переменная. При этом результат выражения, которое находится справа, становится значением этой переменной. Причём тип данных выражения справа не всегда может совпадать с типом переменной, при этом сначала происходит приведение типа к типу переменной. Об этом мы уже знаем.
Приведём несколько примеров присваивания
x = 15;
y = x + 1;
z = x * (y-5);
Мы можем применить несколько операций присваивания одновременно
z = y = x = 5;
Порядок выполнения нескольких операций присваивания в данном случае — справа налево. То есть, сначала результат выражения присваивается переменной x, затем значение переменной x присваивается переменной y а уж затем значение переменной y — переменной z.
Выражения справа от оператора присваивания могут быть также и необычными, представлять собой, например, какие-нибудь условия
y = x < 10;
Так как результат условий бывает лишь двух видов — ИСТИНА или ЛОЖЬ, что в математическом выражении — 1 или 0, то соответствующий результат и присвоится переменной, стоящей справа. Если x будет меньше 10, то присвоится 1, если нет — то 0.
Также присваивание может происходить в самом выражении, например выражении условия
while((y = x)>3)
{
инструкции...
}
или
while((y = x))
{
инструкции...
}
В данном случае в первом примере в условии цикла сначала выполнится выражение в скобках, то есть значение переменной x присвоится переменной y, затем уже значение переменной y проверится на то, что оно больше 3, И если это действительно так, то цикл продолжится, если нет — то выходим из цикла.
Во втором примере всё происходит аналогично, только проверяется равенство единице, так как ИСТИНА — это 1. Две пары скобок обязательны, так как внутренние скобки — это выражение, а внешние — условие цикла. Если будут скобки только одни — получим ошибку.
Помимо базового оператора присваивания в языке C имеются комбинированные операторы присваивания, с помощью которых совместно с операцией присваивания могут выполняться арифметические и другие, в том числе побитовые операции. Такие операторы в комбинированном операторе присваивания ставятся впереди базового оператора присваивания.
Если мы обозначим оператор, комбинируемый с базовым оператором присваивания OP, а операнды справа и слева обозначим o1 b o2, то операция с применением комбинированного оператора присваивания запишется вот так
o1 OP= o2;
А работает комбинированный оператор так: сначала между значением переменной o1 и значением выражения o2 выполняется операция OP, а затем результат этой операции присваивается переменной o1.
То есть команда, записанная нами, будет полностью эквивалентна следующей команде:
o1 = o1 OP o2;
Вот примеры таких операторов:
+= — присваивание со сложением,
-= — присваивание с вычитанием,
*= — присваивание с умножением,
/= — присваивание с делением,
%= — присваивание с делением по модулю,
&= — присваивание с операцией И (AND),
|= — присваивание с операцией ИЛИ (OR),
^= — присваивание с операцией ИСКЛЮЧАЮЩЕЕ ИЛИ (XOR),
>>= — присваивание с битовым сдвигом вправо,
<<= — присваивание с битовым сдвигом влево.
А вот примеры операций с применением таких операторов
x += 5;
y -= x;
z *= x+5;
a /= 3;
b %= 10;
c &= 0x0F;
x |= 0x3A;
y ^= 0x55;
z >>= 2;
a <<= 5;
Стоит обратить внимание вот на эту инструкцию
z *= x+5;
Кто-то вполне может подумать, что она эквивалентна вот такой инструкции
z = z*x+5;
Но, зная правило работы комбинированных операторов присваивания, которое гласит о том, что сначала вычисляется выражение справа от оператора, а уж потом выполняется операция, стоящая перед знаком =, то эквивалентная операция будет вот такая
z = z*(x+5);
Теперь мы немало знаем об операторах присваивания и можем смело приступить к практической части урока.
Проект сделаем из проекта MYPROG15 прошлого занятия и имя ему было присвоено MYPROG16.
Откроем файл main.c и в функции main(), как обычно, удалим весь код тела кроме возврата нуля, останется от него вот это
int main()
{
return 0; //Return an integer from a function
}
Удалим также вот эти константы
#define BIT0 0
#define BIT1 1
#define BIT2 2
#define BIT3 3
#define BIT4 4
#define BIT5 5
#define BIT6 6
#define BIT7 7
Функцию, преобразующую двоичное значение числа в символьный вид, оставим, ещё пригодится.
Добавим в функцию main() следующий код, в котором применим для начала самое простейшее присваивание переменной значения
1 2 3 4 |
int main() { int x = 7; printf("Value is %d", x); |
Проверим, как это работает
Всё работает и всё присвоилось.
Идём дальше. Закомментировав данный код, добавим другой
1 2 3 4 5 6 7 |
int x = 7; int y; int z; y = x + 5; printf("Value is %d\r\n", y); z = x + y; printf("Value is %d\r\n", z); |
Посмотрим результат
Также всё работает.
Теперь попробуем поиграть с условными выражениями
1 2 3 4 5 6 |
int x = 7; int y; y = x < 10; printf("Value is %d\r\n", y); y = x > 10; printf("Value is %d", y); |
А вот и результат наших присваиваний
В первом случае — ИСТИНА, во втором — ЛОЖЬ.
Теперь комбинированные операторы присваивания.
Начнём с арифметических операторов
1 2 3 4 5 6 7 8 9 10 11 12 |
int x = 7; int y = 5; x += 3; printf("Value is %d\r\n", x); y -= x; printf("Value is %d\r\n", y); x *= 5; printf("Value is %d\r\n", x); x /= y; printf("Value is %d\r\n", x); x %= 3; printf("Value is %d\r\n", x); |
Проверим результаты наших операций в консоли
Теперь побитовые операции. В принципе, нет необходимости в примерах со всеми побитовыми операциями. Выполним парочку
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
char str1[35] = {}; unsigned char x=0b10101010, y=0b10001001; int_to_binary(x, str1); printf("%s\r\n", str1); printf(" ^\r\n"); int_to_binary(y, str1); printf("%s\r\n", str1); printf("==========\r\n"); y ^= x; int_to_binary(y, str1); printf("%s\r\n\r\n", str1); int_to_binary(x, str1); printf("%s\r\n", str1); printf(" >> 3\r\n"); printf("==========\r\n"); x >>= 3; int_to_binary(x, str1); printf("%s\r\n", str1); |
Проверим результат
Операторы сработали как надо.
Теперь испытаем несколько присваиваний в одной команде
1 2 3 4 5 |
int x = 3; int y = 7; int z = 7; z = y = x = 5; printf("Values are %d, %d, %d", x, y, z); |
Проверим результат
Также, я думаю, многим не терпится узнать, как же происходит множественное присваивание на уровне процессорных команд. Зайдём в отладку, мы это уже много раз делали и посмотрим код с помощью дизассемблирования
А чтобы было с чем сравнить, то мы нашу команду с множественным присваиванием заменим на три команды с обычным присваиванием
1 2 3 |
z = 5; y = 5; x = 5; |
В данном случае будет уже вот так
Разница видна невооружённым глазом. В первом случае, когда используется множественное присваивание, константа сначала записывается в одну ячейку памяти, затем из неё в регистр, из регистра в другую ячейку памяти, так как команд, пересылающих данные сразу из памяти в память, не существует. Потом из последней ячейки памяти пересылается в следующую также через регистр. Во втором случае, константа сразу заносится в различные ячейки памяти и используется по одной команде на одну ячейку. Что из этого следует. В первом случае скорее всего потеряется больше процессорного времени, чем во втором случае.
Самое главное нам сейчас не экономия процессорного времени, а то, что в отладке путём дизассемблирования мы можем уточнить, как именно происходит та или иная операция языка C, особенно когда возникают споры и кривотолки. Пробовать нужно, конечно, используя различные компиляторы и среды программирования.
Теперь использование присваивания в условных выражениях.
Приведём пару примеров
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
int x = 10; int y; while((y = x)>3) { printf("Value is %d\r\n", y); x--; } printf("\r\n"); x = 10; while((y = x)) { printf("Value is %d\r\n", y); x--; } |
В условии первого цикла значение переменной x присваивается переменной y, затем проверяется, что значение это больше трёх, при выполнении этого условия тело цикла выполняется. А в условии второго цикла также значение переменной x присваивается переменной y, а затем проверяется, что это значение истинно, или равно единице. Только тогда выполняется тело цикла. Поэтому, пока при декрементировании в теле цикла значения переменной x оно не достигнет единицы, цикл будет повторно выполняться.
Проверим это
Всё так и есть.
Итак, на данном уроке мы познакомились с различными операциями присваивания, поняли, что их бывает немало и проверили это на практике, тем самым лишний раз закрепили свои знания.
Всем спасибо за внимание!
Предыдущий урок Программирование на C Следующий урок
Смотреть ВИДЕОУРОК (нажмите на картинку)
большое спасибо за урок.
кажется, присваивание ерунда, а оказалось столько нюансов