What is lvalue?
해당 에러 메세지에 대해 알아보기 전에 lvalue에 대해 간단히 알아보기 위해 MSDN의 lvalue에 대한 정의를 살펴보자.
An lvalue refers to an object that persists beyond a single expression. You can think of an lvalue as an object that has a name. All variables, including nonmodifiable (const) variables, are lvalues. An rvalue is a temporary value that does not persist beyond the expression that uses it.
- MSDN -
MSDN에서 말한 lvalue란 하나의 표현식을 넘어서 존재하는 object이며 쉽게 말해 우리가 값을 할당하고, 변경하며 사용하는 variable인 것이다. 아래의 변수가 lvalue이며 "1 + 1"이라는 표현식의 결과가 rvalue라고 할 수 있을 것이다.
lvalue_var = 1 + 1;
lvalue error
내 경우에는 type cast를 사용한 표현식에 증가 연산자(Increment operator)를 사용하여 해당 에러가 발생하였다. 다음의 코드는 컴파일 시 "lvalue required as increment operand" 에러메세지를 출력하게 된다.
int main(int argc, char **argv, char **envp)
{
int l = 0;
l++;
l = 0;
//l = ((long int)l) + 1;
l = ((long int)l)++;
return 0;
}
$ gcc cast.c
cast.c: In function ‘main’:
cast.c:9:19: error: lvalue required as increment operand
l = ((long int)l)++;
^
type cast와 postfix increment operator간의 우선순위는 후자 쪽이 더 우선한다. 그러므로 괄호를 한번 더 사용하지 않는다면 ++이 먼저 적용되므로 에러가 나지 않지만 type cast를 우선하게 만든다면 에러가 발생하게 된다. 즉 type cast의 결과는 lvalue가 아니라는 의미인 것 이다.
그렇다면 type cast가 어떻게 처리되는지 알기 위해 위의 주석처리를 서로 바꿔서 에러가 나지 않게 하고 해당 assembly 코드를 살펴보았다. 해당 코드를 살펴보면 type cast가 된 값은 레지스터에서 연산되므로, 변수를 의미하는 lvalue가 아니게 된다. ++ 연산자는 lvalue를 operand로 삼으므로 에러가 발생하게 되는 것이다.
(gdb) disas main
Dump of assembler code for function main:
0x00000000004004ed <+0>: push %rbp
0x00000000004004ee <+1>: mov %rsp,%rbp
0x00000000004004f1 <+4>: mov %edi,-0x14(%rbp)
0x00000000004004f4 <+7>: mov %rsi,-0x20(%rbp)
0x00000000004004f8 <+11>: mov %rdx,-0x28(%rbp)
0x00000000004004fc <+15>: movl $0x0,-0x4(%rbp)
0x0000000000400503 <+22>: addl $0x1,-0x4(%rbp)
0x0000000000400507 <+26>: movl $0x0,-0x4(%rbp)
=> 0x000000000040050e <+33>: mov -0x4(%rbp),%eax
0x0000000000400511 <+36>: add $0x1,%eax
0x0000000000400514 <+39>: mov %eax,-0x4(%rbp)
0x0000000000400517 <+42>: mov $0x0,%eax
0x000000000040051c <+47>: pop %rbp
0x000000000040051d <+48>: retq
End of assembler dump.
그러므로 type cast를 사용할 때 이러한 에러 발생 여부를 염두해 두고 사용해야 될 듯 싶다.
참고
- http://en.cppreference.com/w/c/language/operator_precedence
- https://msdn.microsoft.com/en-us/library/f90831hc.aspx
- http://stackoverflow.com/questions/7446489/casting-a-pointer-does-not-produce-an-lvalue-why
- http://stackoverflow.com/questions/21386485/why-isnt-the-result-of-this-cast-an-lvalue
- http://stackoverflow.com/questions/12036921/lvalue-required-on-incrementing-a-void-pointer-even-after-proper-casting