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

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

 

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

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

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

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

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

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

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

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

Пример:

1
2
3
int a = 4; // переменной a присваивается значение 4
int b;
b = a + 2;   // переменной b присваивается значение 6, вычисленное в правой части


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

Пример:
1
2
3
float a = 241.5;
// Перед вычислением остатка от деления a приводится к целому типу
int b = (int)a % 2;  // b = 1


 

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

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

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

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

 

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

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

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

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

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

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

Пример:

1
2
3
4
5
6
int a=2;
int b=3;
int c;
c = a*++b;
// c=8, поскольку в операции умножения
//уже b=4
1
2
3
4
5
6
int a=2;
int b=3;
int d;
d = a*b++;
// d=6, поскольку в операции умножения b=3,
// следующим действием будет b=4

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

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

 

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

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

  • условные;
  • побитовые.

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

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

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

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

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

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

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

  • & конъюнкция (логическое И) — бинарная операция, результат которой равен 1 только когда оба операнда единичны (в общем случае — когда все операнды единичны);
  • | дизъюнкция (логическое ИЛИ) — бинарная операция, результат которой равен 1 когда хотя бы один из операндов равен 1;
  • ~ инверсия (логическое НЕ) — унарная операция, результат которой равен 0 если операнд единичный, и равен 1, если операнд нулевой;
  • ^ исключающее ИЛИ — бинарная операция, результат которой равен 1, если только один из двух операндов равен 1 (в общем случае если во входном наборе операндов нечетное число единиц).

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

a b a & b a | b ~a a ^ b
0 0 0 0 1 0
0 1 0 1 1 1
1 0 0 1 0 1
1 1 1 1 0 0

Пример:

1
2
3
4
5
6
7
unsigned char a = 14;    // a = 0000 1110
unsigned char b = 9;     // b = 0000 1001
unsigned char c, d, e, f;
c = a & b;               // c = 8 = 0000 1000
d = a | b;               // d = 15 = 0000 1111
e = ~a;                  // e = 241 = 1111 0001
f = a ^ b;               // f = 7 = 0000 0111



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

Бит Маска
0 0x01
1 0x02
2 0x04
3 0x08
4 0x10
5 0x20
6 0x40
7 0x80

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

1
2
unsigned char a = 3;
a = a | 0x04;  // a = 7, бит 2 установлен


Для сброса определенного бита необходимо соответствующий бит маски сбросить в 0 и произвести операцию побитового логического И с константой, представляющей собой инверсную маску:
1
2
unsigned char a = 3;
a = a & (~0x02);  // a = 1, бит 1 сброшен


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

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

 

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

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

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

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

Пример:

1
2
3
unsigned char a=6;  // a = 0000 0110
unsigned char b;
b = a >> 1; // b = 0000 0110 >> 1 = 0000 0011 = 3


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


Назад: Язык Си

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

  • Александр
    microcontroller PIC18F25K80 - вывод байта, побитно на 21-ножку(KLINE_OUT). //////////////////////////////////////////////
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    KLINE_OUT = 1;      // start bit

                uint8_t out_data = *ptr++;             //
                for (uint8_t j = 0; j < 8; j++)        // счетчик до 8 бит
                {
                    while (!PIR1bits.TMR2IF) {}        // Флаг таймера
                    PIR1bits.TMR2IF = 0;               // сброс Флага
                    if ((out_data & 0x01) != 0)        // буфер out_data(0х55) 0101 0101 маскируем все биты, кроме этого 0101 010|1|
                    {
                        KLINE_OUT = 0;            
                    }
                    else
                    {
                        KLINE_OUT = 1;
                    }
                    out_data >>= 1;                    // 00101 0101 сдвинуть на 1 бит 00010 1010
                }
    ////////////////////////////////////// прошу закомментировать строки

  • Геннадий
    Елена в данном примере после выполнения действий b = a >> 1,"а" чему осталось равно, 6?: Пример:
    1
    2
    3
    unsigned char a=6;  // a = 0000 0110
    unsigned char b;
    b = a >> 1; // b = 0000 0110 >> 1 = 0000 0011 = 3
    Спасибо.

  • Дмитрий
    Здравствуйте можете объяснить пожалуйста по подробнее про строку: a = (i >> 3) & 0x01; просто данной строкой и ещё несколькими у меня реализуется в программе таблица истинности для логического выражения но я не совсем понял как это работает. Могу для удобства скинуть весь код он не большой.

    • Елена Вставская
      Значение i сдвигается на 3 разряда справа, после чего маской 0x01 гасятся все биты кроме последнего. В младшем бите a получаем то значение, которое было в бите 3 переменной i.

      • Дмитрий
        Можете ещё объяснить
        1
        2
        3
        4
        a = i  &amp; 0x08;
        b = i  &amp; 0x04;
        c = i  &amp; 0x02;
        d = i  &amp; 0x01;

        • Елена Вставская
          Анализируем четыре младших бита переменной i по отдельности

  • Добрый день! Можете дать совет про то, что нужно для лучшего понимания С++ (книги, сайты, видеоуроки т.п.)?

  • Александр
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    #include <stdio.h>
    #include <math.h>

    int main()
    {
        char f;
        int y=3;
        double x ,a , b , c ;
     printf("Введите значение x");
     scanf("%lf" , &x );
     
     printf("Введите значенaе a");
     scanf("%lf" , &a );
     
     printf("Введите значение b");
     scanf("%lf" , &b );
     
     printf("Введите значение c");
     scanf("%lf" , &c );
     
     
     f=(x/c)+(c/x);
     
    if(x<0 , b!= 0);
     f=-a*pow(x,y)-b;
     
     if(x>0 , b=0);
     f=(x-a)/(x-c);}
     
     
     printf("f=%lf", f );
     
     getchar(); getchar();
        
        return 0;
    }

    • Елена Вставская
      1. Почему f имеет тип char, а не double?
      2. Почему в операторе if условия перечислены через запятую? Требуется выполнение по крайней мере одного условия (или) или обоих одновременно (и)?

  • 1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    #include <stdio.h>

    void main()

    {
        int x = 5;
      int y = x + 1;
      int z = x++;

      printf("x= %d\ny= %d\nz= %d", x, y, z);

      return 0;
    }
    а в таком случае вообще x=6 y=6 z=5. Ничего не пойму - почему такие значения?

    • Елена Вставская
      x=5;
      y=x+1, то есть y=6
      z=x++, представляет собой последовательность двух операций z=x и x++. Поскольку x равно 5, то z=x тоже равно 5. x++ увеличивает x на 1, поэтому x становится равным 6

  • А какой тип данных должел быть, чтобы применить логические операции? У меня так получилось: Если я пишу char ddd = 1; . . ddd = ~ ddd; if(ddd==0)..... то ИФ не реагирует на этот ноль, видно стало ddd = 11111110, а это не ноль. А когда написал : char ddd = 0; . . ddd = ~ ddd; ddd = ~ ddd; if(ddd).... ИФ отреагировал. Что изменилось?

    • Елена Вставская
      Так и есть. Тильда означает побитовую инверсию. Используйте восклицательный знак.

  • Александр
    Здравствуйте! У меня такая задача: /*Преобразовать вводимый семиразрядный двоичный код, добавив разряд контроля на четность. Для хранения кодов использовать регистр данных _DX: для исходного кода - его младший байт _DL, для скорректированного - старший байт _DH.*/ Можно ли её реализовать на Си и в каком направлении двигаться, подскажите, пожалуйста.

    • Елена Вставская
      Думаю, можно использовать Си со встроенным ассемблером: https://prog-cpp.ru/asm-c/

  • Извините ни как ни могу понять как работает "! — НЕ (унарная) — требуется невыполнение операции отношения." ? Нашел его вот в таком примере while (!(RCC->CR & RCC_CR_HSERDY));

  • Здравствуйте
    1
    2
    3
    double x;
    for(x; x <= 2.0; x += 0.1)
    printf("%lf\n", x);
    Почему здесь не выводится 2.0, если по условию оно подходит?

    • Елена Вставская
      Это из-за разрядной сетки чисел типа float.
      https://prog-cpp.ru/c-data-types/
      Попробуйте представить свой шаг 0,1 в разрядной сетке, а затем добавлять его к x. И не забудьте, что число типа float не может быть точно равно нулю - разрядная сетка не позволит.

  • Добрый день! Кратко: Си умножение 1 000 000 на 1 000 001, подскажите пожалуйста, как вывести результат ?
    1
    2
    3
    4
    5
    6
    7
    int a, b;

    a = 1 000 000;
    b = 1 000 001;
    a = a * b;
    printf("%d", a);
    return(0);

    • Елена Вставская
      Можно попробовать использовать данные типа long вместо int. Если это не поможет, придется прибегнуть к длинной арифметике: https://prog-cpp.ru/long-mult/

  • Добрый день! Большое вам спасибо, нахожу много полезного на вашем сайте

  • Людмила
    Добрый день! А как понять запись, когда одно число 5 к примеру, а второе 8. И дальше идёт следующая запись: 5<<8?

    • Елена Вставская
      Эта запись означает, что число 5 сдвигается на 8 разрядов влево. Сдвиг влево на 1 разряд соответствует умножению числа на 2. Сдвиг влево на 8 разрядов соответствует умножению числа на 28=256. В итоге получим 5*256 = 1280.

  • Очень понятно написано, спасибо. А нельзя ли расписать побитовые операции с присваиванием. Как раз за этим полез в поиск.

    • Елена Вставская
      a = a | 0x04; то же самое, что a |= 0x04; Ничем не отличается от арифметических операций с присваиванием

  • Евгений
    У вас опечатка в декрементировании Написано: — декрементирование (уменьшение на 1); Должно быть: —— декрементирование (уменьшение на 1); Второй минус потеряли

    • Елена Вставская
      Спасибо, исправила. Движок заменяет два минуса на тире, а я не посмотрела.


    • Елена Вставская
      Обращается к полю структуры, объявленной через указатель

      • Владимир
        Не указаны операции ссылки &, указателя *, массива [], . поле структуры , указатель на структуру ->, sizeof, тернарная операция ? :

  • не понял первый пример, где там деление?
    1
    2
    float a = 241.5; // Перед вычислением остатка от деления a приводится к целому типу
    int b = (int)a % 2;  // b = 1

    • Елена Вставская
      Тут нет деления. Только операция получения остатка от деления - %.

  • Благодарю за понятную статью! Искал материал на тему операций в языке С так вот у вас написано как раз так что любой чайник поймет. И теперь можно смело углубляться в тему. Правда не помешало бы в конце статьи писать конкретные примеры использования содержимого статьи  в реальных задачах а то не совсем понятно галузь применения конкретно побитовых логических операций а так все хорошо!

  • Добрый день.
    Бинарные операции выполняются над двумя объектами... В случае если объекты в левой и правой части операции...
    Немного сбивает с толку использование слова 'объекты'. Есть же замечательное слово "операнд".

  • Информатик
    Извините,но у вас ошибка в таблице лог.операций.Во-первых,в "исключающем или". Во-вторых,в данном примере:
    c = a*++b; // c=8
    поскольку в операции умножения уже
    b=4d = a*b++; // d=6
    поскольку в операции умножения b=3 d=7 А так,спасибо большое,все очень понятно.

    • Спасибо, некорректность в примере исправила. Ошибку в таблице с исключающим ИЛИ тоже.

Добавить комментарий

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