Namespaces
Variants

Value categories

From cppreference.net

Каждое выражение в C (оператор с его аргументами, вызов функции, константа, имя переменной и т.д.) характеризуется двумя независимыми свойствами: типом и категорией значения .

Каждое выражение принадлежит к одной из трёх категорий значений: lvalue, не-lvalue объект (rvalue) и обозначение функции.

Содержание

Lvalue-выражения

Lvalue выражение — это любое выражение с объектным типом , отличным от типа void , которое потенциально обозначает объект (поведение не определено, если lvalue фактически не обозначает объект при вычислении). Другими словами, lvalue выражение вычисляется в идентичность объекта  . Название этой категории значений («левостороннее значение») историческое и отражает использование lvalue выражений в качестве левого операнда оператора присваивания в языке программирования CPL.

Lvalue-выражения могут использоваться в следующих lvalue-контекстах  :

Если выражение 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++ для Категорий значений