3

I am looking for an explanation of how lines L1 and L2 in the code snippet below differ w.r.t l-values, i.e, Why am I getting the: C2105 error in L1, but not in L2?

*s = 'a';
printf("%c\n", *s );
//printf("%c\n", ++(*s)++ ); //L1 //error C2105: '++' needs l-value
printf("%c\n", (++(*s))++);  //L2
printf("%c\n", (*s) );

Note: I got the above result when the code was compiled as a .cpp file. Now, on compilation as .c file, I get the same error C2105 on both lines L1 and L2. Why does L2 compile in C++, and not in C is another mystery :(.

If its of any help, I'm using Visual C++ Express Edition.

Grijesh Chauhan
  • 57,103
  • 20
  • 141
  • 208
VivereJay
  • 71
  • 8
  • 3
    Read [Why `++i++` gives “L-value required error” in C?](http://stackoverflow.com/questions/17850851/why-i-gives-l-value-required-error-in-c) – Grijesh Chauhan Aug 15 '13 at 18:00
  • `(++(*s))++)` compiles? Which compiler you are using? version? – Grijesh Chauhan Aug 15 '13 at 18:09
  • 1
    [Both are l-value errors](http://codepad.org/bbfJmMJm) in C – Grijesh Chauhan Aug 15 '13 at 18:13
  • 1
    L2 provides a valid l-value, L1 does not. It would probably help you to understand that post-increment doesn't actually increment post-*expression* (most think it does, including, unfortunately, all-too-many profs in academia). It saves the current value to a temporary, then increments the l-value, then returns a r-value from the temporary. Since pre-increment requires an l-value, you're getting a correct and accurate error condition. – WhozCraig Aug 15 '13 at 18:13
  • @GrijeshChauhan This is where C and C++ differ. – jrok Aug 15 '13 at 18:13
  • 1
    @GrijeshChauhan; Yes you are right. On GCC 4.7.1, it is giving error for both. – haccks Aug 15 '13 at 18:14
  • 1
    @jrok I concur, so what to do when the OP has *both* languages in the tag-list =P ? – WhozCraig Aug 15 '13 at 18:15
  • @WhozCraig I feel Jrok has a point in [C++ only fist line give error](http://ideone.com/3pWKXE) Why? – Grijesh Chauhan Aug 15 '13 at 18:16
  • Note: the question I linked itself duplicated with **wrong** question. I have already flag that! – Grijesh Chauhan Aug 15 '13 at 18:21
  • Note: `(++(*s))++)` is equivalent to `++*s++` So using prefix increment value of `*s` will be incremented and using postfix `++` value of `s` incremented to point to next location Read: [Find the fault or error](http://stackoverflow.com/questions/17818866/find-the-fault-or-error). Whereas in expression `++(*s)++` post first and prefix applied to `*s` and this is a compilation time error dues to reason in linked answer. – Grijesh Chauhan Oct 08 '13 at 18:43

2 Answers2

4

Compiler see ++(*s)++ as ++((*s)++), as post-increment has higher precedence than pre-increment. After post-incrementation, (*s)++ becomes an r-value and it can't be further pre-incremented (here).
And yes it is not a case of UB (at least in C).
And also read this answer.

For L2 in C++ not giving error because
C++11: 5.3.2 Increment and decrement says:

The operand of prefix ++ is modified by adding 1, or set to true if it is bool (this use is deprecated). The operand shall be a modifiable lvalue. The type of the operand shall be an arithmetic type or a pointer to a completely-defined object type. The result is the updated operand; it is an lvalue, and it is a bit-field if the operand is a bit-field. If x is not of type bool, the expression ++x is equivalent to x+=1.

C++11:5.2.6 Increment and decrement says:

The value of a postfix ++ expression is the value of its operand. [ Note: the value obtained is a copy of the original value —end note ] The operand shall be a modifiable lvalue. The type of the operand shall be an arithmetic type or a pointer to a complete object type. The value of the operand object is modified by adding 1 to it, unless the object is of type bool, in which case it is set to true. The value computation of the ++ expression is sequenced before the modification of the operand object. With respect to an indeterminately-sequenced function call, the operation of postfix ++ is a single evaluation. [ Note: Therefore, a function call shall not intervene between the lvalue-to-rvalue conversion and the side effect associated with any single postfix ++ operator. —end note ] The result is a prvalue. The type of the result is the cv-unqualified version of the type of the operand.

and also on MSDN site it is stated that:

The operands to postfix increment and postfix decrement operators must be modifiable (not const) l-values of arithmetic or pointer type. The type of the result is the same as that of the postfix-expression, but it is no longer an l-value.

Community
  • 1
  • 1
haccks
  • 104,019
  • 25
  • 176
  • 264
  • Pre and post-increment operators have same precedence, but compiler sees ++(*s)++ as ++((*s)++) because the associativity is right-to-left. – VivereJay Aug 15 '13 at 18:11
  • This is not UB but it violates a constraint. – ouah Aug 15 '13 at 18:13
  • 3
    @VivereJay postfix increment operator has higher precedence than prefix increment operator. The right-associativity of postfix and unary operators is just another way to say this. – ouah Aug 15 '13 at 18:15
  • 1
    @haccks don't need to check, the operand of the prefix increment operator has to be a modifiable lvalue in C and the result of the postfix operator is not a lvalue. – ouah Aug 15 '13 at 18:17
  • 1
    @VivereJay look at the standard. The operators are presented in order of precedence (high to low), and §6.5.2 Postfix operators comes before §6.5.3 Unary operators. -- postfix operators have higher precedence than prefix operators -- – Grijesh Chauhan Aug 15 '13 at 18:18
  • @ouah A monstrously valid point. The fact that an error condition is being raised lends validity to that fact that it *is* defined at compile-time (as invalid =). – WhozCraig Aug 15 '13 at 18:20
  • I changed my mind, `(++(*s))++;` is UB (at least in C++). – jrok Aug 15 '13 at 18:38
1

For completeness and quotes from C++ documentation:

Looking at L2, the prefix-increment/decrement returns an l-value. Hence, no error when performing the post-increment. From the C++ documentation for prefix-increment/decrement:

The result is an l-value of the same type as the operand.

Looking at L1, it becomes:

++( ( *s )++ )

... after operand precedence. The post-increment operator by definition evaluates the expression (returning an r-value) and then mutates it. From C++ documentation for post-increment/decrement:

The type of the result is the same as that of the postfix-expression, but it is no longer an l-value.

... and you cannot prefix-increment/decrement an r-value, hence error.

References:

Jacob Pollack
  • 3,703
  • 1
  • 17
  • 39
  • *"The result is an l-value of the same type as the operand"* Citation needed. – jrok Aug 15 '13 at 18:19
  • @jrok, included references. – Jacob Pollack Aug 15 '13 at 18:21
  • That's a C++ reference, and not an authoritative one, at that. – jrok Aug 15 '13 at 18:22
  • @jrok, and the post is tagged as `C++`... otherwise I would not use `C++` references. – Jacob Pollack Aug 15 '13 at 18:23
  • Your answer says: *"From the **C** documentation for prefix-increment/decrement:The result is an l-value of the same type as the operand."* Which is incorrect. In C the result is not an lvalue. – jrok Aug 15 '13 at 18:24
  • @jrok, fixed to clarify C++ -- typo. – Jacob Pollack Aug 15 '13 at 18:24
  • 1
    In case anyone is interested on the C++ side, **C++11 § 5.3.2,p1** "The operand of prefix ++ is modified by adding 1, or set to true if it is bool (this use is deprecated). The operand shall be a modifiable lvalue. The type of the operand shall be an arithmetic type or a pointer to a completely-defined object type. The result is the updated operand; *it is an lvalue*, and it is a bit-field if the operand is a bit-field. If x is not of type bool, the expression ++x is equivalent to x+=1..." – WhozCraig Aug 15 '13 at 18:28