Value categories
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 :
- como el operando del operador de dirección (excepto si el lvalue designa un campo de bits o fue declarado register ).
- como el operando de los operadores de incremento y decremento pre/post.
- como el operando izquierdo del operador de acceso a miembro (punto).
- como el operando izquierdo de los operadores de asignación y asignación compuesta .
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
|