Категории значений
Каждое выражение в C (оператор с его аргументами, вызов функции, константа, имя переменной и т. д.) характеризуется двумя независимыми свойствами: типом и категорией значения.
Каждое выражение относится к одной из трёх категорий значений: lvalue, объект, не являющийся lvalue (rvalue), или обозначатель функции.
Выражения lvalue
Выражение lvalue — это любое выражение с объектным типом, отличным от типа void, которое потенциально обозначает объект (поведение не определено, если при вычислении lvalue фактически не обозначает объект). Другими словами, выражение lvalue вычисляется в идентичность объекта . Название этой категории значений («левое значение») имеет историческое происхождение и отражает использование выражений lvalue в качестве левого операнда оператора присваивания в языке программирования CPL.
Выражения lvalue можно использовать в следующих контекстах lvalue :
- в качестве операнда оператора взятия адреса (кроме случаев, когда lvalue обозначает битовое поле или было объявлено с классом памяти register).
- в качестве операнда операторов инкремента и декремента с префиксной или постфиксной формой.
- в качестве левого операнда оператора доступа к члену (точка).
- в качестве левого операнда операторов присваивания и составного присваивания.
Если выражение lvalue используется в любом контексте, кроме sizeof, _Alignof или перечисленных выше операторов, к lvalue не-массивов любого полного типа применяется преобразование lvalue, моделирующее загрузку значения объекта из памяти по месту его расположения. Аналогично, к lvalue-массивам применяется преобразование массива в указатель при использовании в любом контексте, кроме sizeof, _Alignof, оператора взятия адреса или инициализации массива строковым литералом.
Семантика квалификаторов const/volatile/restrict и атомарных типов применяется только к lvalue (преобразование lvalue удаляет квалификаторы и атомарность).
Следующие выражения являются lvalue:
- идентификаторы, включая именованные параметры функций, если они были объявлены как обозначающие объекты (а не функции или константы перечисления)
- строковые литералы
- (C99) составные литералы
- выражение в скобках, если выражение без скобок является lvalue
- результат оператора доступа к члену (точка), если его левый аргумент является lvalue
- результат доступа к члену через оператор
->указателя - результат оператора разыменования (унарного
*), применённого к указателю на объект - результат оператора индексирования (
[])
Изменяемые выражения lvalue
Изменяемое lvalue — это любое выражение lvalue полного типа, не являющегося типом массива и не квалифицированного как const; если это структура или объединение, оно также не должно рекурсивно содержать членов, квалифицированных как const.
Только изменяемые выражения lvalue можно использовать в качестве аргументов операторов инкремента/декремента и левых аргументов операторов присваивания и составного присваивания.
Выражения-объекты, не являющиеся lvalue
Известные как rvalue , выражения-объекты, не являющиеся lvalue, — это выражения объектных типов, которые не обозначают объекты, а представляют значения, не имеющие идентичности объекта или места хранения. Взять адрес выражения-объекта, не являющегося lvalue, нельзя.
Следующие выражения являются выражениями-объектами, не являющимися lvalue:
- целочисленные, символьные и вещественные константы
- все операторы, для которых не указано, что они возвращают lvalue, в том числе
- любое выражение вызова функции
- любое выражение приведения типа (обратите внимание, что составные литералы, похожие на них, являются lvalue)
- оператор доступа к члену (точка), применённый к структуре/объединению, не являющейся lvalue,
f().x,(x, s1).a,(s1 = s2).m - результаты всех арифметических, реляционных, логических и побитовых операторов
- результаты операторов инкремента и декремента (примечание: префиксные формы являются lvalue в C++)
- результаты операторов присваивания (примечание: в C++ они также являются lvalue)
- условный оператор (примечание: в C++ он является lvalue, если второй и третий операнды — lvalue одного типа)
- оператор запятая (примечание: в C++ он является lvalue, если таким является второй операнд)
- оператор взятия адреса, даже если его действие нейтрализуется применением к результату унарного оператора
*
В особом случае выражения типа void считаются выражениями-объектами, не являющимися lvalue, которые дают значение без представления и не требующее хранения.
| Обратите внимание, что rvalue структуры/объединения, содержащая член (возможно, вложенный) типа массива, действительно обозначает объект с временным временем жизни. Доступ к этому объекту возможен через выражения lvalue, образующиеся при индексировании члена-массива или при разыменовании указателя, полученного в результате преобразования члена-массива из массива в указатель. | (начиная с C99) |
Выражение-обозначатель функции
Обозначатель функции (идентификатор, введённый объявлением функции) — это выражение функционального типа. При использовании в любом контексте, кроме оператора взятия адреса, sizeof и _Alignof (последние два оператора приводят к ошибкам компиляции при применении к функциям), обозначатель функции всегда преобразуется в указатель на функцию, не являющийся lvalue. Обратите внимание, что оператор вызова функции определён для указателей на функции, а не для самих обозначателей функций.
Источники
- Стандарт C23 (ISO/IEC 9899:2024):
- 6.3.2.1 Lvalues, arrays, and function designators (с. 48–49)
- Стандарт C17 (ISO/IEC 9899:2018):
- 6.3.2.1 Lvalues, arrays, and function designators (с. 40)
- Стандарт C11 (ISO/IEC 9899:2011):
- 6.3.2.1 Lvalues, arrays, and function designators (с. 54–55)
- Стандарт C99 (ISO/IEC 9899:1999):
- 6.3.2.1 Lvalues, arrays, and function designators (с. 46)
- Стандарт C89/C90 (ISO/IEC 9899:1990):
- 3.2.2.1 Lvalues and function designators
См. также
| Документация C++ для категорий значений |
© cppreference.com
Licensed under the Creative Commons Attribution-ShareAlike Unported License v3.0.
https://en.cppreference.com/c/language/value_category