Foreversoft.ru

IT Справочник
0 просмотров
Рейтинг статьи
1 звезда2 звезды3 звезды4 звезды5 звезд
Загрузка...

Язык си сдвиг влево

Операции в языке Си

Над объектами в языке Си могут выполняться различные операции:

  • операции присваивания;
  • операции отношения;
  • арифметические;
  • логические;
  • сдвиговые операции.

Результатом выполнения операции является число.

Операции могут быть бинарными или унарными.
Бинарные операции выполняются над двумя объектами, унарные — над одним.

Операция присваивания

Операция присваивания обозначается символом = и выполняется в 2 этапа:

  • вычисляется выражение в правой части;
  • результат присваивается операнду, стоящему в левой части:

объект = выражение;

В случае если объекты в левой и правой части операции присваивания имеют разные типы используется операция явного приведения типа.
объект = (тип)выражение;

Операции отношения

Основные операции отношения:

  • == эквивалентно — проверка на равенство;
  • != не равно — проверка на неравенство;
  • меньше;
  • > больше;
  • меньше или равно;
  • >= больше или равно.

Операции отношения используются при организации условий и ветвлений. Результатом этих операций является 1 бит, значение которого равно 1 , если результат выполнения операции — истина, и равно 0 , если результат выполнения операции — ложь.

Арифметические операции

Основные бинарные операции, расположенные в порядке уменьшения приоритета:

  • * — умножение;
  • / — деление;
  • + — сложение;
  • — вычитание;
  • % — остаток от целочисленного деления.

Основные унарные операции:

  • ++ — инкрементирование (увеличение на 1);
  • –– — декрементирование (уменьшение на 1);
  • — изменение знака.

Результат вычисления выражения, содержащего операции инкрементирования или декрементирования, зависит от того, где расположен знак операции (до объекта или после него). Если операция расположена до объекта, то сначала происходит изменение значения переменной на 1, а потом это значение используется для выполнения следующих операций. Если операция ++ или расположена после переменной, то сначала выполняется операция, а потом значение переменной изменяется на 1.

Бинарные арифметические операции могут быть объединены с операцией присваивания:

  • объект *= выражение; // объект = объект * выражение
  • объект /= выражение; // объект = объект / выражение
  • объект += выражение; // объект = объект + выражение
  • объект -= выражение; // объект = объект — выражение
  • объект %= выражение; // объект = объект % выражение

Логические операции

Логические операции делятся на две группы:

Условные логические операции чаще всего используются в операциях проверки условия if и могут выполняться над любыми объектами. Результат условной логической операции:

  • 1 если выражение истинно;
  • 0 если выражение ложно.

Вообще, все значения, отличные от нуля, интерпретируются условными логическими операциями как истинные.

Основные условные логические операции:

  • && — И (бинарная) — требуется одновременное выполнение всех операций отношения;
  • || — ИЛИ (бинарная) — требуется выполнение хотя бы одной операции отношения;
  • ! — НЕ (унарная) — требуется невыполнение операции отношения.

Побитовые логические операции оперируют с битами, каждый из которых может принимать только два значения: 0 или 1.

Основные побитовые логические операции в языке Си:

инверсия (логическое НЕ) — унарная операция, результат которой равен 0 если операнд единичный, и равен 1, если операнд нулевой;

  • ^ исключающее ИЛИ — бинарная операция, результат которой равен 1, если только один из двух операндов равен 1 (в общем случае если во входном наборе операндов нечетное число единиц).
  • Для каждого бита результат выполнения операции будет получен в соответствии с таблицей.

    a

    aba & ba | ba ^ b
    1
    1111
    111
    1111

    a; // e = 241 = 1111 0001
    f = a ^ b; // f = 7 = 0000 0111

    Побитовые операции позволяют осуществлять установку и сброс отдельных битов числа. С этой целью используется маскирование битов . Маски, соответствующие установке каждого бита в байте, представлены в таблице

    БитМаска
    0x01
    10x02
    20x04
    30x08
    40x10
    50x20
    60x40
    70x80

    Для установки определенного бита необходимо соответствующий бит маски установить в 1 и произвести операцию побитового логического ИЛИ с константой, представляющей собой маску:

    Для сброса определенного бита необходимо соответствующий бит маски сбросить в 0 и произвести операцию побитового логического И с константой, представляющей собой инверсную маску:

    0x02); // a = 1, бит 1 сброшен

    Бинарные побитовые логические операции могут быть объединены с операцией присваивания:

    • объект &= выражение; // объект = объект & выражение
    • объект |= выражение; // объект = объект | выражение
    • объект ^= выражение; // объект = объект ^ выражение

    Сдвиговые операции

    Операции арифметического сдвига применяются в целочисленной арифметике и обозначаются как:

    • >> — сдвиг вправо;
    • — сдвиг влево.

    Общий синтаксис осуществления операции сдвига:
    объект = выражение сдвиг КоличествоРазрядов;

    Арифметический сдвиг целого числа вправо >> на 1 разряд соответствует делению числа на 2.
    Арифметический сдвиг целого числа влево на 1 разряд соответствует умножению числа на 2.

    Комментариев к записи: 25

    ddd; if(ddd==0). то ИФ не реагирует на этот ноль, видно стало ddd = 11111110, а это не ноль. А когда написал : char ddd = 0; . . ddd =

    ddd; if(ddd). ИФ отреагировал. Что изменилось?

    Урок №45. Побитовые операторы

    Обновл. 30 Дек 2019 |

    Примечание: Для некоторых этот материал может показаться сложным. Если вы застряли или что-то не понятно — пропустите этот урок (и следующий), в будущем сможете вернуться и разобраться детальнее. Он не столь важен для прогресса в изучении C++, как другие уроки, и изложен здесь в большей мере для общего развития.

    Побитовые операторы манипулируют отдельными битами в пределах переменной.

    Зачем нужны побитовые операторы?

    В далёком прошлом компьютерной памяти было очень мало и ею сильно дорожили. Это было стимулом максимально разумно использовать каждый доступный бит. Например, в логическом типе данных bool есть всего лишь два возможных значения (true и false), которые могут быть представлены одним битом, но по факту занимают целый байт памяти! А это, в свою очередь, из-за того, что переменные используют уникальные адреса памяти, а они выделяются только в байтах. Переменная bool занимает 1 бит, а другие 7 тратятся впустую.

    Используя побитовые операторы, можно создавать функции, которые позволят уместить 8 значений типа bool в переменной размером 1 байт, что значительно сэкономит потребление памяти. В прошлом такой трюк был очень популярен. Но сегодня, по крайней мере, в прикладном программировании, это не так.

    Теперь памяти существенно больше и программисты обнаружили, что лучше писать код так, чтобы было проще и понятнее его поддерживать, нежели усложнять его ради незначительной экономии памяти. Поэтому спрос на использование побитовых операторов несколько спал, за исключением случаев, когда необходима ну уже максимальная оптимизация (например: научные программы, которые используют огромное количество данных; игры, где манипуляции с битами могут быть использованы для дополнительной скорости; встроенные программы, где память по-прежнему ограничена).

    Есть 6 побитовых операторов:

    x

    Оператор Символ Пример Операция
    Побитовый сдвиг влево>x >> yВсе биты в x смещаются вправо на y бит
    Побитовое НЕВсе биты в x меняются на противоположные
    Побитовое И&x & yКаждый бит в x И каждый бит в y
    Побитовое ИЛИ|x | yКаждый бит в x ИЛИ каждый бит в y
    Побитовое исключающее ИЛИ (XOR)^x ^ yКаждый бит в x XOR каждый бит в y

    В побитовых операциях следует использовать только целочисленные типы данных unsigned, так как C++ не всегда гарантирует корректную работу побитовых операторов с целочисленными типами signed.

    Правило: При работе с побитовыми операторами используйте целочисленные типы данных unsigned.

    Побитовый сдвиг влево ( >)

    Примечание: В следующих примерах мы будем работать с 4-битными двоичными значениями.

    В C++ количество используемых бит основывается на размере типа данных (в 1 байте находятся 8 бит). Оператор побитового сдвига влево ( 3 мы имеем в виду «сдвинуть биты влево в литерале 3 на одно место».

    Рассмотрим число 3, что в двоичной системе = 0011:

    В последнем третьем случае, один бит перемещается за пределы самого литерала! Биты, сдвинутые за пределы двоичного числа, теряются навсегда.

    Оператор побитового сдвига вправо (>>) сдвигает биты вправо. Например:

    12 = 1100
    12 >> 1 = 0110 = 6
    12 >> 2 = 0011 = 3
    12 >> 3 = 0001 = 1

    В третьем случае мы снова переместили бит за пределы литерала. Он также потерялся навсегда.

    Хотя в примерах выше мы смещаем биты в литералах, мы также можем смещать биты и в переменных:

    Работа с регистрами AVR микроконтроллера на Си, битовые операции

    Показаны принципы работы с отдельными битами регистра порта в AVR микроконтроллере. Подробно рассмотрены битовые операции и операции сдвига битов в языке Си. Приведены примеры установки и сброса битов в регистре порта, чтение состояния битов и их инверсии.

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

    Структура байта

    Мы знаем что один байт представляет собою 8 бит, а каждый бит это — 1 или 0, биты в байте считаются справа налево. Бит 1 является младшим, а бит 8 — старшим.

    1 Байт
    8 (старший бит)7654321 (младший бит)

    Порты, байты и биты

    Представьте себе на минуточку, что регистр порта в микроконтроллере — это аппаратная панель, на которой расположены один за другим восемь одинаковых переключателей, каждый из которых может иметь два состояния: включен (1) или выключен (0).

    В языке Си для AVR, установка значения 1 для бита в порте — это как перевод нужного переключателя в состояние «включено». На выходе канала для указанного порта, к которому подвязан наш виртуальный выключатель, появится высокий уровень, а это в свою очередь подаст напряжение на какое-то устройство, например на светодиод, который сразу же засветится.

    Названия каналов в порте микроконтроллера отсчитываются с нуля (0). Ниже приведен пример битовой структуры порта PORTD:

    Регистр порта PORTD, 1 байт
    Номер бита в регистре87654321
    Канал портаPD7PD6PD5PD4PD3PD2PD1PD0

    Аналогично по структуре выглядят и другие порты — PORTA, PORTB, DDRD, PINA.

    Предустановленные значения констант PD0, PD1, PB5, PA4 (и многих других) для каждого типа AVR-микроконтроллера указаны в специальном заголовочном файле библиотеки avr-libc.

    Например, чтобы вывести на экран значения всех констант из IO-файла для микроконтроллера ATmega8, содержащих сочетание символов «PD» (ищем константы для порта D, PORTD), достаточно выполнить следующую команду:

    Увидим следующий результат:

    Теперь, при использовании константы PD0 в своей программе на Си, вы знаете что в ней содержится число 0, а в PD3 — 3 и т.д.

    Операции битового сдвига

    А сейчас, давайте подробно и с примерами разберемся с тем, как работают операторы битового сдвига.

    Существует несколько разновидностей операций битового сдвига:

    • логический (сдвинутые в направлении биты теряются, а освободившиеся позиции заполняются нулями);
    • арифметический (сдвиг влево аналогичен логическому, а при сдвиге вправо — свободные позиции заполняются значениями крайнего левого бита, который еще называют знаковым);
    • циклический (потерянные с одной стороны биты перемещаются на освободившиеся позиции с другой, как замкнутое кольцо).

    Операторы битового сдвига в языке программирования Си обозначаются как «>>» и » >») битов в числе с отрицательным знаком (signed) выполняется арифметический сдвиг — освободившиеся позиции слева заполняются единичками (перенос знака). Это важно помнить!

    • Bin — от слова Binary, двичная система счисления;
    • Dec — от слова Decimal, десятичная система счисления;
    • Hex — от слова Hexadecimal, шестнадцатиричная система счисления.

    Для примера выполним сдвиги битов в разных числах, предварительно представив их в двоичном виде.

    Для числа 1 (Dec, в десятичной системе 1) — 00000001 (Bin, в двоичной системе 0b00000001):

    Сдвиг влево на один разряд выполняет умножение числа на 2, а сдвиг вправо — деление числа на 2.

    Для числа 209 (Dec, в десятичной системе 209) — 11010001 (Bin, в двоичной системе 0b11010001):

    • 209 = 1110001;
    • 209 > 5 = 6 (00000110)

    Для пересчета из одной системы счисления в другую в Linux удобно использовать калькулятор, об этом я уже раньше писал.

    Битовые операторы в языке Си

    То как двигать биты в байте мы теперь знаем, дальше разберемся с битовыми операторами в Си:

    » (логическое НЕ) или инверсия — унарная операция, результат которой равен 0 если операнд равен 1, и наоборот — результат равен 1, если операнд равен 0;

  • «^» (исключающее ИЛИ, XOR) — бинарная операция, результат которой равен 1 в том случае если только один из двух операндов равен 1.
  • Рассмотрим примеры битовых операций над числами 209, 7 и их битовыми представлениями:

    1101 0001 (209)
    &

    0000 0111 (7)
    —————-
    0000 0001 (1)

    1101 0001 (209)
    |
    0000 0111 (7)
    —————-
    1101 0111 (215) 1101 0001 (209)

    —————-
    0010 1110 (46) 1101 0001 (209)
    ^
    0000 0111 (7)
    —————-
    1101 0110 (214)

    Как видите, битовые операции позволяют установить или сбросить отдельные биты числа.

    Установка битов в регистре порта

    А теперь немного практики, давайте сделаем установку 6-го бита в регистре порта PORTB что в свою очередь установит высокий уровень для канала PB5 (6-й бит в регистре). Допустим что сейчас в регистре PORTB содержится число 136, которое в битовом представлении выглядит как 10001000 (высокий уровень на каналах PB7 и PB3).

    Чтобы установить 6-й бит (1001000) мы будем использовать битовую операцию логического ИЛИ в комплексе с битовой маской.

    Что такое битовая маска? — по сути это специально подготовленное число, состоящее из требуемой конфигурации битов, которое в сочетании с некоторой операцией над битами другого числа позволяет установить или сбросить биты в последнем.

    Для получения битовой маски, при помощи которой позже будет установлен один бит, мы выполним левосторонний сдвиг битов числа 1 (00000001) на 5 разрядов:

    0000 0001 (1)
    —————-
    0010 0000 (32)

    В результате битовой операции получим число 32 (00100000), это и есть наша битовая маска. Хочу заметить что это число равняется числу 2 в 5-й степени, каждый сдвиг разряда влево умножает результат на 2.

    Теперь нам останется выполнить битовую операцию ИЛИ над текущим числом в регистре и получившимся числом-маской:

    1000 1000 (136)
    |
    0010 0000 (32)
    —————-
    1010 1000 (168)

    А теперь сравните состояние регистра перед операцией и после — все состояния битов сохранены и дополнительно установлен 6-й бит.

    Для установки 6-го бита и последующей записи числа в регистр порта PORTB (установка высокого уровня для канала PB5) в нашем примере можно использовать любую из следующих конструкций операторов, они все выполняют идентичную задачу:

    • PORTB = PORTB | 32;
    • PORTB = PORTB | (1 0000 0001 (1)
      —————-
      0001 0000 (16)

    Маска готова, получили число 16 (00010000), 2 в 4-й степени. Выполним инверсию битов:

    0001 0000 (16)

    Готово, осталось применить маску к содержимому регистра порта PORTB используя битовую операцию «&»:

    1001 1101 (157)
    &
    1110 1111 (239)
    —————-
    1000 1101 (141)

    Теперь в содержимом регистра PORTD значение 5-го бита установлено в 0 с сохранением положений остальных бит. В языке Си данные операции можно выполнить используя любую из приведенных ниже, идентичных по результату команд:

    16;

  • PORTD = PORTD & 239;
  • PORTD = PORTD &

    ( 1 0000 0001 (1)
    —————-
    0000 0100 (4)

    Теперь применим битовую операцию «&» (логическое И) к содержимому регистра PORTD и получившейся маске:

    1001 0101 (149)
    &
    0000 0100 (4)
    —————-
    0000 0100 (4)

    В результате выражения получим число 4 (0000 0100).

    В языке Си все числа которые НЕ равны «нулю» (-100, -5, 1, 500) являются логической истиной (True), а 0 — логической ложью (False).

    Результат нашего выражения — число 4, которое является логической истиной (True), а это значит что 3-й разряд регистра PORTD содержит единицу.

    Вот как будет выглядеть данное выражение из двух логических операций на языке Си:

    Такое выражение можно использовать в условных операторах (if) и операторах циклов (while), например:

    Для проверки состояния бита в регистре на ноль (0) используем такую же конструкцию, только к результату выражения применим логическую операцию инверсии «!» (логическое НЕ).

    Логическая операция «!» переворачивает значение с правды (True) на ложь (False), и наоборот. В отличие от битовой операции инверсии, которая переворачивает биты с 1 на 0 и наоборот, логическая операция инверсии оперирует с логическими значениями: правда (True) на ложь (False).

    1 = True0 = False122 = True(149 & (1 0000 0001 (1)
    —————-
    0010 0000 (32)

    Применим маску к содержимому регистра порта PORTD:

    1011 1010 (186)
    ^
    0010 0000 (32)
    —————-
    1001 1010 (154)

    Как видите, 6-й бит в байте регистра, который раньше был 1, сейчас установлен в 0 (101 1010). Теперь осталось записать число в регистр порта и задачу можно считать выполненной. Примеры использования такой конструкции на языке Си:

    • PORTD = PORTD ^ 32;
    • PORTD = PORTD ^ (1 >» и других, но один раз хорошо разобравшись и попробовав на практике вы всегда будете иметь понятие что и как работает, откуда берется и что содержит.

    Логические и битовые операции присутствуют во многих языках программирования, не только в Си, так что данный опыт будет вам полезен если вы также будете работать и с другими языками программирования.

    Язык си сдвиг влево

    Этот шаг посвящен использованию битовых операций.

    Использование битовых операций обычно свойственно программистам, работающим на языке ассемблера (например, если необходимо проверить разряды регистров состояний или маскировать некоторые из разрядов при приеме и передаче информации). Однако, для некоторых программ необходима (или, по крайней мере, полезна) возможность манипулировать отдельными разрядами в байте или слове. Например, часто варианты режимов устройства ввода-вывода устанавливаются байтом, в котором каждый разряд действует как признак «включено-выключено».

    В языке C++ существуют следующие операции, выполняющиеся над разрядами:


      унарная операция :

        инверсия битов (

      );

  • бинарные операции :
    • битовое «И» (&);
    • битовое «ИЛИ» (|);
    • битовое исключающее «ИЛИ» (^);
    • сдвиг влево ( сдвиг вправо (>>);

  • Остановимся на данных операциях более подробно.

    1. Инверсия битов (поразрядное отрицание, дополнение до единицы) инвертирует биты, т.е. каждый бит со значением 1 получает значение 0 и наоборот.

    2. Битовое «И» сравнивает последовательно разряд за разрядом два операнда. Для каждого разряда результат равен 1, тогда и только тогда, когда оба соответствующих разряда операндов равны 1. Так, например,

    3. Битовое «ИЛИ» сравнивает последовательно разряд за разрядом два своих операндов. Для каждого разряда результат равен 1 тогда и только тогда, когда любой из соответствующих разрядов операндов равны 1. Так, например,

    4. Битовое исключающее «ИЛИ» сравнивает последовательно разряд за разрядом два своих операндов. Для каждого разряда результат равен 1, если один из двух (но не оба) соответствующих разрядов операндов равен 1. Так, например,

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

    5. Сдвиг влево сдвигает разряды левого операнда влево на число позиций, указанное правым операндом. Освобождающиеся позиции заполняются нулями, а разряды, сдвигаемые за левый предел левого операнда, теряются . Поэтому, например,

    Таким образом, х сдвигает х влево на 2 позиции, заполняя освобождающиеся позиции нулями (эквивалентно умножению на 4).

    6. Сдвиг вправо сдвигает разряды левого операнда вправо на число позиций, указанное правым операндом. Разряды, сдвигаемые за правый предел левого операнда, теряются. Для чисел со знаком результат зависит от компилятора. Освобождающиеся позиции могут заполнятся нулями или значением знакового разряда (самого левого).

    Для значений без знака имеем

    Эти две операции выполняют сдвиг, а также эффективное умножение и деление на степени числа 2.

    Результат работы программы:

    Комментарии . Целые константы, начинающиеся с цифры 0, являются восьмеричными числами . Восьмеричное представление целых чисел особенно удобно, когда приходится работать с поразрядными операциями, так как восьмеричные числа легко переводятся в двоичные. В этой задаче числа 01,02,03 соответствуют числам 1, 2 и 3, так что появление восьмеричных чисел служит намеком, что программа рассматривает значения x, y и z как последовательности двоичных цифр.

    Вследствие приоритетов операций: k = (x|(y&z)); . Самое внутреннее выражение вычисляется первым.

    Читать еще:  Массивы си шарп
    Ссылка на основную публикацию
    Adblock
    detector