Namespaces
Variants

Assignment operators

From cppreference.net

Операторы присваивания и составного присваивания — это бинарные операторы, которые изменяют переменную слева, используя значение справа.

Оператор Название оператора Пример Описание Эквивалент
= базовое присваивание a = b a становится равным b Н/Д
+ = присваивание сложения a + = b a становится равным сумме a и b a = a + b
- = присваивание вычитания a - = b a становится равным разности a и b a = a - b
* = присваивание умножения a * = b a становится равным произведению a и b a = a * b
/ = присваивание деления a / = b a становится равным частному от деления a на b a = a / b
% = присваивание по модулю a % = b a становится равным остатку от деления a на b a = a % b
& = присваивание побитового И a & = b a становится равным побитовому И a и b a = a & b
| = присваивание побитового ИЛИ a | = b a становится равным побитовому ИЛИ a и b a = a | b
^ = присваивание побитового исключающего ИЛИ a ^ = b a становится равным побитовому исключающему ИЛИ a и b a = a ^ b
<<= присваивание побитового сдвига влево a <<= b a становится равным a сдвинутому влево на b a = a << b
>>= присваивание побитового сдвига вправо a >>= b a становится равным a сдвинутому вправо на b a = a >> b

Содержание

Простое присваивание

Простые выражения оператора присваивания имеют вид

lhs = rhs

где

lhs - modifiable lvalue выражение любого полного объектного типа
rhs - выражение любого типа неявно преобразуемое в lhs или совместимое с lhs

Присваивание выполняет неявное преобразование значения rhs в тип lhs , после чего заменяет значение в объекте, обозначенном lhs , преобразованным значением rhs .

Присваивание также возвращает то же значение, которое было сохранено в lhs (так что выражения вида a = b = c возможны). Категория значения оператора присваивания является не-lvalue (так что выражения вида ( a = b ) = c недопустимы).

rhs и lhs должны удовлетворять одному из следующих условий:

  • оба операнда lhs и rhs имеют арифметические типы , в этом случае lhs может быть квалифицирован как volatile или atomic (since C11)
  • оба операнда lhs и rhs имеют указатели на совместимые (игнорируя квалификаторы) типы, или один из указателей является указателем на void, и преобразование не добавляет квалификаторы к указываемому типу. lhs может быть квалифицирован как volatile или restrict (since C99) или atomic (since C11) .
  • lhs является (возможно квалифицированным или atomic (since C11) ) указателем, а rhs является нулевым указателем-константой, таким как NULL или значение типа nullptr_t (since C23)
  • lhs имеет тип (возможно квалифицированный или атомарный (since C11) ) _Bool и rhs является указателем или значением типа nullptr_t (since C23)
(since C99)
  • lhs имеет тип (возможно квалифицированный или атомарный) nullptr_t и rhs имеет тип nullptr_t
(начиная с C23)

Примечания

Если rhs и lhs перекрываются в памяти (например, они являются членами одного и того же union), поведение не определено, если перекрытие не является точным и типы не являются совместимыми .

Хотя массивы не являются присваиваемыми, массив, обёрнутый в структуру, может быть присвоен другому объекту того же (или совместимого) типа структуры.

Побочный эффект обновления lhs упорядочен после вычисления значений, но не побочных эффектов самих lhs и rhs , а вычисления операндов, как обычно, не упорядочены относительно друг друга (поэтому выражения вроде i = ++ i ; являются неопределёнными)

Присваивание удаляет дополнительный диапазон и точность из выражений с плавающей запятой (см. FLT_EVAL_METHOD ).

В C++ операторы присваивания являются lvalue-выражениями, в отличие от C.

#include <stdio.h>
int main(void)
{
    // целые числа
    int i = 1, j = 2, k = 3; // инициализация, не присваивание
    i = j = k;   // значения i и j теперь 3
//  (i = j) = k; // Ошибка: требуется lvalue
    printf("%d %d %d\n", i, j, k);
    // указатели
    const char c = 'A'; // инициализация; не присваивание
    const char *p = &c;  // инициализация; не присваивание
    const char **cpp = &p; // инициализация; не присваивание
//  cpp = &p;   // Ошибка: char** не конвертируется в const char**
    *cpp = &c;  // OK, char* конвертируется в const char*
    printf("%c \n", **cpp);
    cpp = 0;    // OK, нулевая константа указателя конвертируется в любой указатель
    // массивы
    int arr1[2] = {1,2}, arr2[2] = {3, 4};
//  arr1 = arr2; // Ошибка: нельзя присвоить массиву
    printf("arr1[0]=%d arr1[1]=%d arr2[0]=%d arr2[1]=%d\n",
            arr1[0],   arr1[1],   arr2[0],   arr2[1]);
    struct { int arr[2]; } sam1 = { {5, 6} }, sam2 = { {7, 8} };
    sam1 = sam2; // OK: можно присваивать массивы, обернутые в структуры
    printf("%d %d \n", sam1.arr[0], sam1.arr[1]);
}

Вывод:

3 3 3
A
arr1[0]=1 arr1[1]=2 arr2[0]=3 arr2[1]=4
7 8

Составное присваивание

Выражения операторов составного присваивания имеют вид

lhs op rhs

где

op - один из * = , / = % = , + = - = , <<= , >>= , & = , ^ = , | =
lhs , rhs - выражения с арифметическими типами (где lhs может быть квалифицированным или атомарным), за исключением случаев, когда op является + = или - = , которые также допускают указательные типы с теми же ограничениями, что и + и -

Выражение lhs @= rhs точно такое же, как lhs = lhs @ ( rhs ) , за исключением того, что lhs вычисляется только один раз.

Если lhs имеет atomic тип, операция ведет себя как единая атомарная операция чтения-модификации-записи с порядком памяти memory_order_seq_cst .

Для целочисленных атомарных типов составное присваивание @ = эквивалентно:

T1* addr = &lhs;
T2 val = rhs;
T1 old = *addr;
T1 new;
do { new = old @ val } while (!atomic_compare_exchange_strong(addr, &old, new);
(since C11)
#include <stdio.h>
int main(void)
{
    int x = 10; 
    int hundred = 100; 
    int ten = 10; 
    int fifty = 50; 
    printf("%d %d %d %d\n", x, hundred, ten, fifty);
    hundred *= x; 
    ten     /= x; 
    fifty   %= x; 
    printf("%d %d %d %d\n", x, hundred, ten, fifty);
    return 0;
}

Вывод:

10 100 10 50
10 1000 1 0

Ссылки

  • Стандарт C17 (ISO/IEC 9899:2018):
  • 6.5.16 Операторы присваивания (стр: 72-73)
  • Стандарт C11 (ISO/IEC 9899:2011):
  • 6.5.16 Операторы присваивания (стр. 101-104)
  • Стандарт C99 (ISO/IEC 9899:1999):
  • 6.5.16 Операторы присваивания (стр. 91-93)
  • Стандарт C89/C90 (ISO/IEC 9899:1990):
  • 3.3.16 Операторы присваивания

Смотрите также

Приоритет операторов

Общие операторы
присваивание инкремент
декремент
арифметические логические сравнения доступа к членам
доступа
прочие

a = b
a + = b
a - = b
a * = b
a / = b
a % = b
a & = b
a | = b
a ^ = b
a <<= b
a >>= b

++ a
-- a
a ++
a --

+ a
- a
a + b
a - b
a * b
a / b
a % b
~a
a & b
a | b
a ^ b
a << b
a >> b

! a
a && b
a || b

a == b
a ! = b
a < b
a > b
a <= b
a >= b

a [ b ]
* a
& a
a - > b
a. b

a ( ... )
a, b
( type ) a
a ? b : c
sizeof


_Alignof
(начиная с C11)
(до C23)

alignof
(начиная с C23)

Смотрите также

Документация C++ для Операторов присваивания