Assignment operators
Операторы присваивания и составного присваивания — это бинарные операторы, которые изменяют переменную слева, используя значение справа.
| Оператор | Название оператора | Пример | Описание | Эквивалент |
|---|---|---|---|---|
| = | базовое присваивание | 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 имеют совместимый struct или union тип, или..
- 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)
|
(since C99) |
| (начиная с 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) |
Вывод:
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
|
+
a
|
!
a
|
a
==
b
|
a
[
b
]
|
a
(
...
)
|
Смотрите также
|
Документация C++
для
Операторов присваивания
|