Namespaces
Variants

Value categories

From cppreference.net

Cada expresión en C (un operador con sus argumentos, una llamada a función, una constante, un nombre de variable, etc.) se caracteriza por dos propiedades independientes: un tipo y una categoría de valor .

Cada expresión pertenece a una de las tres categorías de valor: lvalue, objeto no-lvalue (rvalue) y designador de función.

Contenidos

Expresiones Lvalue

La expresión lvalue es cualquier expresión con tipo objeto diferente al tipo void , que potencialmente designa un objeto (el comportamiento es indefinido si un lvalue no designa realmente un objeto cuando se evalúa). En otras palabras, la expresión lvalue se evalúa como la identidad del objeto  . El nombre de esta categoría de valor ("valor izquierdo") es histórico y refleja el uso de expresiones lvalue como operando izquierdo del operador de asignación en el lenguaje de programación CPL.

Las expresiones lvalue pueden usarse en los siguientes contextos lvalue  :

Si una expresión lvalue se utiliza en cualquier contexto distinto a sizeof , _Alignof , o los operadores mencionados anteriormente, los lvalues no-arreglo de cualquier tipo completo experimentan lvalue conversion , que modela la carga en memoria del valor del objeto desde su ubicación. De manera similar, los lvalues de arreglo experimentan array-to-pointer conversion cuando se utilizan en cualquier contexto distinto a sizeof , _Alignof , el operador address-of, o la inicialización de arreglo desde un literal de cadena.

La semántica de los calificadores const / volatile / restrict y los tipos atómicos se aplican únicamente a lvalues (la conversión lvalue elimina los calificadores y remueve la atomicidad).

Las siguientes expresiones son lvalues:

  • identificadores, incluyendo parámetros nombrados de funciones, siempre que hayan sido declarados como designadores de objetos (no funciones o constantes de enumeración)
  • literales de cadena
  • (C99) literales compuestos
  • expresión entre paréntesis si la expresión sin paréntesis es un lvalue
  • el resultado de un operador de acceso a miembro (punto) si su argumento izquierdo es lvalue
  • el resultado de un acceso a miembro a través del puntero -> operator
  • el resultado del operador de indirección (unario * ) aplicado a un puntero a objeto
  • el resultado del operador de subíndice ( [] )

Expresiones de lvalue modificables

Un lvalue modificable es cualquier expresión lvalue de tipo completo, no-array que no esté const -calificado, y, si es una estructura/unión, no tiene miembros que estén const -calificados, recursivamente.

Solo las expresiones de lvalue modificables pueden usarse como argumentos para incremento/decremento, y como argumentos del lado izquierdo de los operadores de asignación y asignación compuesta.

Expresiones de objeto no lvalue

Conocidos como rvalues  , las expresiones de objeto no lvalue son las expresiones de tipos de objeto que no designan objetos, sino valores que no tienen identidad de objeto ni ubicación de almacenamiento. No se puede tomar la dirección de una expresión de objeto no lvalue.

Las siguientes expresiones son expresiones de objeto no lvalue:

  • constantes enteras, de caracteres y de punto flotante
  • todos los operadores no especificados para devolver lvalues, incluyendo
  • cualquier expresión de llamada a función
  • cualquier expresión de conversión (nota: los literales compuestos, que parecen similares, son lvalues)
  • operador de acceso a miembro (punto) aplicado a una estructura/unión que no es lvalue, f ( ) . x , ( x, s1 ) . a , ( s1 = s2 ) . m
  • resultados de todos los operadores aritméticos, relacionales, lógicos y bit a bit
  • resultados de los operadores de incremento y decremento (nota: las formas pre- son lvalues en C++)
  • resultados de los operadores de asignación (nota: también son lvalues en C++)
  • el operador condicional (nota: es lvalue en C++ si tanto el segundo como el tercer operando son lvalues del mismo tipo)
  • el operador coma (nota: es lvalue en C++ si el segundo operando lo es)
  • el operador dirección-de, incluso si se neutraliza mediante aplicación al resultado del operador unario *

Como caso especial, las expresiones de tipo void se asumen como expresiones de objeto no lvalue que producen un valor que no tiene representación y no requiere almacenamiento.

Nótese que un valor r de struct/union que tiene un miembro (posiblemente anidado) de tipo array de hecho designa un objeto con duración temporal . Este objeto puede ser accedido mediante expresiones lvalue que se forman indexando el miembro array o mediante indirección a través del puntero obtenido por la conversión de array-a-puntero del miembro array.

(since C99)

Expresión designadora de función

Un designador de función (el identificador introducido por una declaración de función ) es una expresión de tipo función. Cuando se utiliza en cualquier contexto distinto al operador dirección-de, sizeof , y _Alignof (los dos últimos generan errores de compilación cuando se aplican a funciones), el designador de función siempre se convierte en un puntero no lvalue a función. Nótese que el operador de llamada a función está definido para punteros a funciones y no para los designadores de función en sí mismos.

Referencias

  • Estándar C23 (ISO/IEC 9899:2024):
  • 6.3.2.1 Lvalues, arrays, and function designators (p: 48-49)
  • Estándar C17 (ISO/IEC 9899:2018):
  • 6.3.2.1 Lvalues, arrays, and function designators (p: 40)
  • Estándar C11 (ISO/IEC 9899:2011):
  • 6.3.2.1 Lvalues, arrays, and function designators (p: 54-55)
  • Estándar C99 (ISO/IEC 9899:1999):
  • 6.3.2.1 Lvalues, arrays, and function designators (p: 46)
  • Estándar C89/C90 (ISO/IEC 9899:1990):
  • 3.2.2.1 Lvalues y designadores de función

Véase también

Documentación de C++ para Categorías de valor