• C

L-Value question


I have a fundamental question about C syntax.  In my copy of MSVC++.NET,

int xx = 0;  // definition

(xx=3) = 4;  // compiles

xx=3=4;    // does not compile, left operand must be an L value

my question is why *don't* I get an Lvalue error on the previous line.  In no way did I expect "(xx=3)" to result in an L-value.  I understand it's an R-value (i.e., can be the source of another assignment), didn't expect an L-value (i.e., corresponds to a memory location and can be the target of another assignment).

Is the rule always that (A=B) results in an L-Value with the same memory location as A?  Is this consistent for all flavors/compilers of C, or is this a microsoft-ism.

I'm studying the C standard a little bit, so bonus points if you can reference the relevant content in the standard.  Thanks very much for any thoughts.
riceman0Asked:
Who is Participating?
 
phoffricConnect With a Mentor Commented:
>> I'm studying the C standard a little bit, so bonus points if you can reference the relevant content in the standard.
    I hope you have first read "The ANSI C Programming Language" by Kernighan and Ritchie (just to make life easier for you).
>> In no way did I expect "(xx=3)" to result in an L-value.
    Earlier, I expressed surprise also. The VS not only compiled with (xx=3) = 4; but resulted in xx having a value of 4 (this is not surprising given that it compiled. I am going to run one more VS variation.

    From the C99 standard:

6.3.2.1 Lvalues, arrays, and function designators
Except when it is the operand of the sizeof operator, the unary & operator, the ++ operator, the -- operator, or the left operand of the . operator or an assignment operator, an lvalue that does not have array type is converted to the value stored in the designated object (and is no longer an lvalue).

6.5.16 Assignment operators
An assignment expression has the value of the left operand after the assignment, but is not an lvalue.
0
 
milindsmCommented:
Read this,

http://msdn.microsoft.com/en-us/library/bkbs2cds%28VS.80%29.aspx

It clearly says, "An l-value expression in parentheses" can be a l-value
0
 
riceman0Author Commented:

Thanks.  That verifies my observation, however that is microsoft literature, could theoretically still be a microsoftism (although I'd be surprised).  

And in fact it adds a little confusion, I'm not sure why the parentheses make a difference... x=3 should evaluate the same as (x=3), both or neither should be L-values or R-values, right?

Ideally, if someone could relate this to the C standard that would be great.  I've read this and totally missed this rule.  

http://www.open-std.org/JTC1/SC22/WG14/www/docs/n1256.pdf
0
Improved Protection from Phishing Attacks

WatchGuard DNSWatch reduces malware infections by detecting and blocking malicious DNS requests, improving your ability to protect employees from phishing attacks. Learn more about our newest service included in Total Security Suite today!

 
phoffricCommented:
The = binary operator has right to left associativity.
So,
xx=3=4;
when fully parenthesized becomes:
xx=(3=4);  // 3 is not an lvalue
0
 
milindsmConnect With a Mentor Commented:
Precedence of '=' operator is Right->Left so in the last expression. xx=3=4, it first tries to assign 4 to 3  which is an invalid statement. Now, lets talk about (xx=3)=4. Here too we have assignment operator but its precedence is overridden by () thus (xx=3) get evaluated first and then since result of an assignment is always a l-value, 4 is then assigned to this l-value

I hope this clears your doubt...!!!
0
 
phoffricCommented:
>> since result of an assignment is always a l-value
Where in the c-spec did you find this?
>> "An l-value expression in parentheses" can be a l-value
Although this comes from MS, it happens to be true. For example,
   char ptr[] = "hello world";
   ( ptr[3] ) = 'x';
0
 
phoffricCommented:
I was a little surprised that (xx=3) = 4;  // compiles under Visual Studio 2008 Express
  (xx=3) = 4;  // does not compiles under cygwin
Error:
  lvalue.c:11: error: lvalue required as left operand of assignment

(xx=3) definitely will return the value of xx (which is 3), but I didn't expect it to return the address of xx.
0
 
phoffricCommented:
It's happens that in if statements, one forgets to use the == equality operator, and accidentally uses the = assignment operator. In if statements like this
     if( c = returnedValue ) {...}
the program compiles and may appear to work for awhile (either because c is the same value as returnedValue , or the bug goes unnoticed).

In the below code, one might mean to say:
       if( ( c = f() ) == -99 ) {...}
which means assign c the return value of f(), and then see if this returned value is -99.

But typos and oversights occur; and the == is accidentally replaced with an = assignment operator as shown in code below.

In VS 2008 Express, the output is:
     c test is true; c = -99
But, luckily, in cygwin, we get the compiler error:
     lvalue.c:6: error: lvalue required as left operand of assignment
int f(void) { return 1; }
int main() {
   char c;
   if( ( c = f() ) = -99 ) {
      printf(" c test is true; c = %d\n", c);
   }
   else {
      printf(" c test is false; c = %d\n", c);
   }
}

Open in new window

0
 
peetmCommented:
>>It's happens that in if statements, one forgets to use the == equality operator, and accidentally uses the = assignment operator. In if statements like this
     if( c = returnedValue ) {...}


Which is why you might often see something like this:

    if(returnedValue == c) {...}

so that if one writes

    if(returnedValue = c) {...}


You'll hopefully get a compilation error ... of course, this does require that returnedValue (the semantics seems to suggest that this isn't the case) isn't a reference!
0
 
Infinity08Connect With a Mentor Commented:
As phoffric already said : the accepted answer http:#30689145 does not describe how things work in C. And, since this question was posted in the C zone, it is not accurate.

What http:#30689145 describes, is how things work in C++. There is a difference between C and C++ in this respect :


In C, an assignment expression is NOT an lvalue. These will work :

        x = y = 5;
        x = (y = 5);

but these won't :

        (x = y) = 5;
        (x = 3) = 5;
        x = 3 = 5;

Refer to paragraph 6.5.16 in the C standard :

        "An assignment operator stores a value in the object designated by the left operand. An
        assignment expression has the value of the left operand after the assignment, but is not an
        lvalue."

In C++ however, an assignment expression IS an lvalue, so these will work :

        x = y = 5;
        x = (y = 5);
        (x = y) = 5;
        (x = 3) = 5;

but this one still won't :

        x = 3 = 5;

Refer to paragraph 5.17 in the C++ standard :

        "The assignment operator (=) and the compound assignment operators all group right-to-left. All require a modifiable
        lvalue as their left operand and return an lvalue with the type and value of the left operand after the assignment has taken
        place."
0
 
phoffricCommented:
>>  if(returnedValue = c) {...}
peetm: thanks for bringing that up. In fact, if returnedValue is a literal value, then in one project's coding standards (which were audited by both internal and external reviewers), we were required to use this form to prevent such compilable code from getting into executables.

But I never did understand why the same rule applied to other test operators such as >.
0
 
phoffricCommented:
Yeah, Infinity08, I keep reusing old VS projects forgetting to start with a C project (i.e., one with .c source code extensions). Dang cockpit error! I'll probably remember to use pure C VS projects from now on. :)
0
 
peetmCommented:
>>But I never did understand why the same rule applied to other test operators such as >.

Me neither - seems like overkill and a probable *source* of problems, c.f. if(n > 10) vs. if(10 > n)
0
 
itsmeandnobodyelseCommented:
>>>> I keep reusing old VS projects forgetting to start with a C project
You must not start with a C project. I am using a C++ console project with a few cpp files and one .c file (normally deactivated). If activated the .c  was compiled with ANSI C compiler.
0
 
itsmeandnobodyelseCommented:
>>>>    if(returnedValue = c) {...}
>>>> You'll hopefully get a compilation error ...

Hopefully not, cause I sometimes use like

  if (ret = func())

or

 if ((ret = func()) != XYZ_ERR)

which would then fail for the same reason.

   

0
 
riceman0Author Commented:
Fascinating.  Sorry to accept early.  (More often I'm yelled at for being late.)
0
 
peetmCommented:
>>Hopefully not, cause I ..


Yes, but you *know* that I meant having a constant on the lhs.
0
 
milindsmCommented:
ok... I give up.... please take away my points....!!!!
0
 
phoffricCommented:
>> ok... I give up.... please take away my points....!!!!
Not acceptable - giving up is not an option! IMO, this was subtle. I have been corrected many times. In fact, I wasn't aware of the C++ difference in semantics. We are Exchanging!
0
 
brijesh_iaeCommented:
Hi,

In simple term, a lvalue means anything to whom we can assign a value. When compiler sees the expression
           (xx=3) = 4;  // compiles
it first evaluates the expression within (xx=3) since the precedence of () is more than =(after ()). In this epression xx is a lvalue and compiler assigns 3 to xx. Once 3 is assigned to xx, xx is now used as lvalue to 4 and now 4 is assigned to xx.

In expression xx=3=4, the compiler uses the associativity because of the same precedence of the = operator within the expression. The associativity of = operator is from right to left. So 3 = 4 is evaluated first. Here 3 is not a lvalue because we can't assign 4 to 3. Therefore compiler gives an error.
xx=3=4;  
0
 
Infinity08Commented:
@brijesh_iae : that would be true for C++, but not for C. This has already extensively been discussed above.
0
Question has a verified solution.

Are you are experiencing a similar issue? Get a personalized answer when you ask a related question.

Have a better answer? Share it in a comment.

All Courses

From novice to tech pro — start learning today.