Spec-Zone.ru › C

Категории значений

Каждая выражение в 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-квалификаторов и типов atomic применимы только к 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++)
    • результаты операторов присваивания (примечание: также lvalue в C++)
    • условный оператор (примечание: является lvalue в C++, если оба второй и третий операнды являются lvalue одного и того же типа)
    • оператор запятой (примечание: является lvalue в C++, если второй операнд является)
    • оператор взятия адреса, даже если он нейтрализован применением к результату унарного * оператора

В качестве специального случая выражения типа void предполагаются выражения не-lvalue объекта, которые дают значение, не имеющее представления и не требующее хранения.

Обратите внимание, что rvalue структуры/объединения, имеющей член (возможно, вложенный) типа массива, фактически обозначает объект с временем жизни. К этому объекту можно получить доступ через выражения lvalue, образующие индексацию члена массива или косвенный доступ через указатель, полученный путём преобразования массива в указатель члена массива.

Выражение указателя на функцию

Указатель на функцию (идентификатор, введённый объявлением функции) — это выражение типа функции. При использовании в любом контексте, отличном от оператора взятия адреса, sizeof и _Alignof (последние два генерируют ошибки компиляции, когда применяются к функциям), указатель на функцию всегда преобразуется в указатель на не-lvalue функцию. Обратите внимание, что оператор вызова функции определён для указателей на функции, а не для самих указателей на функцию.

Ссылки

  • Стандарт C17 (ISO/IEC 9899:2018):
    • 6.3.2.1 Lvalues, arrays, and function designators (p: 40)
  • Стандарт C11 (ISO/IEC 9899:2011):
    • 6.3.2.1 Lvalues, arrays, and function designators (p: 54-55)
  • Стандарт C99 (ISO/IEC 9899:1999):
    • 6.3.2.1 Lvalues, arrays, and function designators (p: 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/w/c/language/value_category

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API