operaciones - operadores de asignacion en c++
¿Cuál es el punto de evaluar el operando izquierdo del operador de asignación en C? (5)
Según la norma ISO C11 - 6.5.16.3, dice que
- Un operador de asignación almacena un valor en el objeto designado por el operando izquierdo. Una expresión de asignación tiene el valor del operando izquierdo después de la asignación, pero no es un valor l. El tipo de una expresión de asignación es el tipo que tendría el operando izquierdo después de la conversión de lvalue. El efecto secundario de actualizar el valor almacenado del operando izquierdo se secuencia después de los cálculos de valor de los operandos izquierdo y derecho. Las evaluaciones de los operandos no son posteriores.
Así que supongo que esto significa que, por ejemplo,
int x = 10;
x = 5 + 10;
- El operando izquierdo
x
se evalúa a 10 y el operando derecho se evalúa a 15. - El valor del operando derecho se almacena en el objeto designado por el operando izquierdo
x
.
Pero si el propósito de la asignación es almacenar el valor evalado del operando derecho (como en el paso 2), ¿por qué es necesaria la evaluación del operando izquierdo? ¿Cuál es el punto de evaluar el operando izquierdo?
Como si no
int x, y, z;
x = y = z = 5;
¿trabajo? (La asignación " z=5
" debe dar el valor (r-) de z
a la asignación " y= ...
", que luego debe dar el valor de y
a la asignación " x= ...
". )
El comportamiento bajo el capó es:
- Cargue el valor 5 en un registro (y no reutilice este registro para nada más hasta el paso 7, a continuación)
- Cargar la dirección de
z
en un registro (Esto es lo que significa "z
" cuando se usa como valor l.) - Almacenar 5 en la dirección de
z
. 5 es ahora el valor de "z
". Recuerde que las CPU funcionan con valores y direcciones, no con "z
". La etiqueta variable "z
" es un referente amigable para el ser humano a una dirección de memoria que contiene un valor. Dependiendo de cómo se use, desearemos su valor (cuando obtengamos el valor dez
) o su dirección (cuando reemplazemos el valor dez
). - Cargar la dirección de
y
en un registro. - Almacene el valor de
z
(5) en la dirección dey
. (Uno debería / podría optimizar y reutilizar el "5" desde el primer paso.) - Cargue la dirección de
x
en un registro. - Almacene el valor de
y
(5) en la dirección dex
.
Cuando x
se evalúa como un lvalue
, no se evalúa como 10. Se evalúa como un lvalue
donde se puede almacenar el valor de RHS. Si el LHS no se evalúa como un valor de lvalue
, la declaración sería un error.
De la norma C99 (6.3.2.1/1):
Un lvalue es una expresión (con un tipo de objeto distinto de vacío) que potencialmente designa un objeto; Si un valor de l no designa un objeto cuando se evalúa, el comportamiento no está definido.
La evaluación de la LHS como un valor lime es trivial cuando tiene una variable simple, como
x = 10;
Sin embargo, puede ser más complejo.
double array[10];
int getIndex(); // Some function that can return an index based
// on other data and logic.
array[getIndex()+1] = 10.0;
// This looks like a function call that returns a value.
// But, it still evaluates to a "storage area".
int *getIndex2() { return(&array[0]); }
*getIndex2()=123.45; // array[0]=123.45
Si getIndex()
devuelve 5
, entonces el LHS se evalúa como un valor de l que designa el 7º elemento de la matriz.
Solo para convencerme (si no lo he hecho) desde el punto de vista de "Judas", lo que justifica que mi publicación solo responda a la pregunta simple en su caso simple.
pequeña prueba que muestra que en su ejemplo simple gcc hace exactamente lo que necesita, no más:
código:
int main()
{
int x = 10;
x = 5 + 10;
return x;
}
construir con depuración
K:/jff/data/python//c>gcc -g -std=c11 -c assign.c
objdump con código C / asm entremezclado
K:/jff/data/python//c>objdump -d -S assign.o
assign.o: file format pe-x86-64
Disassembly of section .text:
0000000000000000 <main>:
int main()
{
0: 55 push %rbp
1: 48 89 e5 mov %rsp,%rbp
4: 48 83 ec 30 sub $0x30,%rsp
8: e8 00 00 00 00 callq d <main+0xd>
int x = 10;
d: c7 45 fc 0a 00 00 00 movl $0xa,-0x4(%rbp)
x = 5 + 10;
14: c7 45 fc 0f 00 00 00 movl $0xf,-0x4(%rbp)
return x;
1b: 8b 45 fc mov -0x4(%rbp),%eax
}
1e: 90 nop
1f: 48 83 c4 30 add $0x30,%rsp
23: 5d pop %rbp
24: c3 retq
25: 90 nop
26: 90 nop
27: 90 nop
28: 90 nop
29: 90 nop
2a: 90 nop
2b: 90 nop
2c: 90 nop
2d: 90 nop
2e: 90 nop
2f: 90 nop
Como se indica en las otras respuestas (agradables), no está dispuesto a parafrasear, pero si la expresión es más compleja, la dirección para almacenar el valor debe calcularse, por lo que es necesaria una evaluación de algún tipo.
EDITAR:
Con un código un poco más complejo:
int main()
{
int x[3];
int i = 2;
x[i] = 5 + 10;
return x[i];
}
Desmontaje:
Disassembly of section .text:
0000000000000000 <main>:
int main()
{
0: 55 push %rbp
1: 48 89 e5 mov %rsp,%rbp
4: 48 83 ec 30 sub $0x30,%rsp
8: e8 00 00 00 00 callq d <main+0xd>
int x[3];
int i = 2;
d: c7 45 fc 02 00 00 00 movl $0x2,-0x4(%rbp)
x[i] = 5 + 10;
14: 8b 45 fc mov -0x4(%rbp),%eax <== hey, could be more optimized here: movl $0x2,%eax covers line+above line :)
17: 48 98 cltq
19: c7 44 85 f0 0f 00 00 movl $0xf,-0x10(%rbp,%rax,4) <== this line holds the left-operand evaluation, in a way, %rax is used to offset the array address
20: 00
return x[i];
21: 8b 45 fc mov -0x4(%rbp),%eax
24: 48 98 cltq
26: 8b 44 85 f0 mov -0x10(%rbp,%rax,4),%eax
}
2a: 90 nop
2b: 48 83 c4 30 add $0x30,%rsp
2f: 5d pop %rbp
30: c3 retq
Tiene expresiones no triviales en el lado izquierdo de =
que deben evaluarse todo el tiempo. Aquí hay unos ejemplos.
int array[5];
int *ptr = malloc(sizeof(int) * 5);
*ptr = 1; // The lhs needs to evaluate an indirection expression
array[0] = 5; // The lhs needs to evaluate an array subscript expression
for (int i = 0; i < 5; ++i) {
*ptr++ = array[i]; // Both indirection and postincrement on the lhs!
}
// Here, we want to select which array element to assign to!
int test = (array[4] == 0);
(test ? array[0] : array[1]) = 5; // Both conditional and subscripting!
Un "operando de la izquierda" puede ser mucho más complicado que su simple x
en su ejemplo (lo que, ciertamente, no es un desafío para evaluar):
*(((unsigned long*)target)++) = longValue;
Definitivamente necesita un poco de evaluación en el LHS. Su oración citada se refiere a lo que debe hacerse en el lado izquierdo de la tarea para encontrar el valor apropiado para recibir la tarea.