Value categories
Каждое выражение в C (оператор с его аргументами, вызов функции, константа, имя переменной и т.д.) характеризуется двумя независимыми свойствами: типом и категорией значения .
Каждое выражение принадлежит к одной из трёх категорий значений: lvalue, не-lvalue объект (rvalue) и обозначение функции.
Содержание |
Lvalue-выражения
Lvalue выражение — это любое выражение с объектным типом , отличным от типа void , которое потенциально обозначает объект (поведение не определено, если lvalue фактически не обозначает объект при вычислении). Другими словами, lvalue выражение вычисляется в идентичность объекта . Название этой категории значений («левостороннее значение») историческое и отражает использование lvalue выражений в качестве левого операнда оператора присваивания в языке программирования CPL.
Lvalue-выражения могут использоваться в следующих lvalue-контекстах :
- в качестве операнда оператора взятия адреса (за исключением случаев, когда lvalue обозначает битовое поле или было объявлено с register ).
- в качестве операнда префиксных/постфиксных операторов инкремента и декремента .
- в качестве левого операнда оператора доступа к члену (оператор точки).
- в качестве левого операнда операторов присваивания и составного присваивания .
Если выражение lvalue используется в любом контексте, кроме
sizeof
,
_Alignof
или перечисленных выше операторов, не-массивные lvalues любого полного типа подвергаются
lvalue conversion
, которая моделирует загрузку значения объекта из его местоположения в память. Аналогично, массивные lvalues подвергаются
array-to-pointer conversion
при использовании в любом контексте, кроме
sizeof
,
_Alignof
, оператора взятия адреса или инициализации массива строковым литералом.
Семантика
const
/
volatile
/
restrict
-квалификаторов и
atomic
типов применяется только к lvalue (lvalue-преобразование удаляет квалификаторы и атомарность).
Следующие выражения являются lvalue:
- идентификаторы, включая именованные параметры функций, при условии, что они были объявлены как обозначающие объекты (не функции или константы перечисления)
- строковые литералы
- (C99) составные литералы
- выражение в скобках, если выражение без скобок является lvalue
- результат оператора доступа к члену (точка), если его левый аргумент является lvalue
-
результат доступа к члену через указатель
->оператор -
результат операции разыменования (унарный
*оператор), примененной к указателю на объект -
результат оператора индексации (
[])
Модифицируемые lvalue-выражения
Изменяемый lvalue — это любое lvalue-выражение полного не-массивного типа, которое не является const -квалифицированным, и, если это структура/объединение, не имеет членов, которые являются const -квалифицированными, рекурсивно.
Только модифицируемые lvalue-выражения могут использоваться в качестве аргументов для инкремента/декремента, а также в качестве левых операндов операторов присваивания и составных операторов присваивания.
Выражения объектов, не являющиеся lvalue
Известные как rvalues , не-lvalue объектные выражения - это выражения объектных типов, которые обозначают не объекты, а значения, не имеющие объектной идентичности или местоположения в памяти. Адрес не-lvalue объектного выражения не может быть взят.
Следующие выражения являются не-lvalue объектными выражениями:
- целочисленные, символьные и вещественные константы
- все операторы, не указанные как возвращающие lvalues, включая
-
- любое выражение вызова функции
- любое выражение приведения типа (обратите внимание, что составные литералы, которые выглядят похоже, являются lvalue)
- оператор доступа к члену (точка), примененный к не-lvalue структуре/объединению, f ( ) . x , ( x, s1 ) . a , ( s1 = s2 ) . m
- результаты всех арифметических, реляционных, логических и побитовых операторов
- результаты операторов инкремента и декремента (примечание: префиксные формы являются lvalue в C++)
- результаты операторов присваивания (примечание: также являются lvalue в C++)
- условный оператор (примечание: является lvalue в C++, если оба второго и третьего операнда являются lvalue одного типа)
- оператор запятая (примечание: является lvalue в C++, если второй операнд является lvalue)
-
оператор взятия адреса, даже если нейтрализован применением к результату унарного
*оператора
В качестве особого случая, выражения типа void считаются не-lvalue объектными выражениями, которые возвращают значение, не имеющее представления и не требующее хранения.
|
Обратите внимание, что rvalue структуры/объединения, имеющее член (возможно, вложенный) типа массива, фактически обозначает объект с временным временем жизни . Этот объект может быть доступен через lvalue-выражения, формируемые индексацией члена-массива или через косвенную адресацию с помощью указателя, полученного преобразованием массива в указатель члена-массива. |
(since C99) |
Выражение-обозначение функции
Обозначение функции (идентификатор, введённый
объявлением функции
) является выражением функционального типа. При использовании в любом контексте, кроме оператора взятия адреса,
sizeof
, и
_Alignof
(последние два генерируют ошибки компиляции при применении к функциям), обозначение функции всегда преобразуется в не-lvalue указатель на функцию. Отметим, что оператор вызова функции определён для указателей на функции, а не для самих обозначений функций.
Ссылки
- Стандарт C23 (ISO/IEC 9899:2024):
-
- 6.3.2.1 Lvalues, массивы и обозначения функций (стр: 48-49)
- Стандарт C17 (ISO/IEC 9899:2018):
-
- 6.3.2.1 Lvalues, массивы и обозначения функций (стр. 40)
- Стандарт C11 (ISO/IEC 9899:2011):
-
- 6.3.2.1 L-значения, массивы и обозначения функций (стр: 54-55)
- Стандарт C99 (ISO/IEC 9899:1999):
-
- 6.3.2.1 Lvalues, массивы и обозначения функций (стр. 46)
- Стандарт C89/C90 (ISO/IEC 9899:1990):
-
- 3.2.2.1 Lvalues и обозначения функций
Смотрите также
|
Документация C++
для
Категорий значений
|