For example:
int x[100];
void *p;
x[0] = 0x12345678;
x[1] = 0xfacecafe;
x[3] = 0xdeadbeef;
p = x;
((int *) p) ++ ;
printf("The value = 0x%08x", *(int*)p);
Compiling the above generates an lvalue required error on the line with the ++ operator.
The cast creates a temporary pointer of type int *. You can't increment a temporary as it doesn't denote a place to store the result.
In C and C++ standardese, (int *)p is an rvalue, which roughly means an expression that can only occur on the right-hand side of an assignment.
p on the other hand is an lvalue, which means it can validly appear on the left-hand side of an assignment. Only lvalues can be incremented.
The expression ((int *) p) treats the pointer stored inside the variable p is a pointer to int. If you want to treat the variable itself as a pointer to int variable (and then increment it), use a reference cast:
((int *&) p) ++ ;
Thanks to larsmans for pointing to the right direction.
I took the liberty of digging deeper into this. So for future reference, according to sections 6.5.2.4 and 6.5.4 of the C99 standard (http://www.open-std.org/jtc1/sc22/WG14/www/docs/n1256.pdf):
6.5.2.4 Postfix increment and decrement operators
Constraints
The operand of the postfix increment
or decrement operator shall have
qualified or unqualified real or
pointer type and shall be a modifiable
lvalue....
6.5.4 Cast operators
..
..
[Footnote] 89) A cast
does not yield an lvalue. Thus, a cast
to a qualified type has the same
effect as a cast to the unqualified
version of the type.
Note: This only applies to C. C++ may handle casts differently.
You can get the intended result with
p = (int*)p + 1;
Using the increment operator on a dereferenced pointer to p, which is an lvalue, also works:
(*(int**)&p)++;
However, the latter is not portable, since (void*)p might not have the same representation as (int*)p.
Rvalue expression ((int *) p) creates and temporary of type int* on which operator ++ cannot be applied.
++ requires an lvalue as its operand.
As #FredOverflow mentions lvalues and rvalues have very little to do with assignment.
Arrays are lvalues still they cannot be assigned to because they are non-modifiable.
std::string("Prasoon") is an rvalue expression still it can occur on the left side of assignment operator because we are allowed to call member functions( operator = in this case) on temporaries.
Related
Is address computation on a null pointer defined behavior in C++? Here's a simple example program.
struct A { int x; };
int main() {
A* p = nullptr;
&(p->x); // is this undefined behavior?
return 0;
}
Thanks.
EDIT Subscripting is covered in this other question.
&(p->x); // is this undefined behavior?
Standard is a bit vague regarding this:
[expr.ref] ... The expression E1->E2 is converted to the equivalent form (*(E1)).E2;
[expr.unary.op] The unary * operator ... the result is an lvalue referring to the object ... to which the expression points.
There is no explicit mention of UB in the section. The quoted rule does appear to conflict with the fact that the null pointer doesn't point to any object. This could be interpreted that yes, behaviour is undefined.
[expr.unary.op] The result of the unary & operator is a pointer to its operand. ... if the operand is an lvalue of type T, the resulting expression is a prvalue of type “pointer to T” whose result is a pointer to the designated object ([intro.memory]).
Again, no designated object exists. Note that at no point is the operand lvalue converted to an rvalue, which would definitely have been UB.
Back in 2000 there was CWG issue to clarify whether indirection through null is undefined. The proposed resolution (2004), that would clarify that indirection through null is not UB, appears to not have been added to the standard so far.
However whether it is or isn't UB doesn't matter much since you don't need to do this. At the very least, the resulting pointer will be invalid and thus useless.
If you were planning to convert the pointer to an integer to get the offset of the member, there is no need to do this because you can instead us the offsetof macro from the standard library, which doesn't have UB.
&(p[1]); // undefined?
Here, behaviour is quite clearly undefined:
[expr.sub] ... The expression E1[E2] is identical (by definition) to *((E1)+(E2)), except that in the case of an array operand, the result is an lvalue if that operand is an lvalue and an xvalue otherwise.
[expr.add] When an expression J that has integral type is added to or subtracted from an expression P of pointer type, the result has the type of P.
If P evaluates to a null pointer value and J evaluates to 0 (does not apply)
Otherwise, if P points to an array element (does not apply)
Otherwise, the behavior is undefined.
&(p[0]); // undefined?
As per previous rules, the first option applies:
If P evaluates to a null pointer value and J evaluates to 0, the result is a null pointer value.
And now we are back to the question of whether indirection through this null is UB. See the beginning of the answer.
Still, doesn't really matter. There is no need to write this, since this is simply unnecessarily complicated way to write sizeof(int) * i (with i being 1 and 0 respectively).
I suspect this is true for all primitive types in C/C++.
For example, if you do this:
((unsigned int*)0x1234) = 1234;
The compiler will not let it pass. Whereas if you do this
((data_t*)0x1234 )->s = 1234;
where data_t is a struct, the compiler allows it.
This seems to be the case for at least two compilers I experimented on, one ARM GCC, one TDM-GCC.
Why is this?
The first code snippet doesn't work because the left hand side is not an lvalue. It is only a pointer value, and pointers by themselves are not lvalues.
The second code snippet works because a pointer is being dereferenced, and a dereferenced pointer is an lvalue. It may not be immediately clear from the syntax this is the case, so let's rewrite this:
((data_t*)0x1234 )->s = 1234;
As:
(*(data_t*)0x1234).s = 1234;
Now we can see that the value which is casted to a pointer is dereferenced to an lvalue of struct type, and a member of that struct is subsequently accessed and assigned to.
This is described in section 6.5.2.3p4 of the C standard regarding the -> operator:
A postfix expression followed by the -> operator and an identifier
designates a member of a structure or union object. The value
is that of the named member of the object to which the first
expression points, and is an lvalue. If the first expression is a
pointer to a qualified type, the result has the so-qualified
version of the type of the designated member.
Regarding the first snippet, section 6.5.4p5 regarding the typecast operator states:
Preceding an expression by a parenthesized type name converts
the value of the expression to the named type. This construction is
called a cast. 104) A cast that specifies no conversion has
no effect on the type or value of an expression.
Where footnote 104 states:
A cast does not yield an lvalue. Thus, a cast to a qualified
type has the same effect as a cast to the unqualified version
of the type.
So this describes why the first snippet won't compile but the second snippet will.
However, treating an arbitrary value as a pointer and dereferencing it is implementation defined behavior at best, and most likely undefined behavior.
Your examples are:
((unsigned int*)0x1234) = 1234;
((data_t*)0x1234 )->s = 1234;
Neither ((unsigned int*)0x1234) nor ((data_t*)0x1234 ) is an lvalue, and you can't assign to either of them.
More generally, the prefix of -> doesn't have to be an lvalue. But prefix->member is always an lvalue, whether prefix is or not. Similarly, *p is an value whether p is an lvalue or not.
Ok, so I've been learning about lvalues and rvalues - could somebody well versed in C/C++ tell me if my thinking is correct?
Consider the code:
int i = 3;
int j = i;
Here we have two lvalues i and j, when i is assigned to j it becomes an implicit rvalue because a copy of i is stored in j. If however the code looked like:
int i = 3;
int j = &i;
Would both j and &i be lvalues because they are both physical addresses in memory? The way I understand it is that rvalues are temporary data, whereas lvalues have a physical/referenceable memory address.
Any clarification on this would be great!
The variable i never stops being an lvalue. If you can apply the address-of operator to something (like you do in the second example) then it's an lvalue.
Also in the second example &i is a pointer to i, and has the type int*. You have a type mismatch there between the declaration of j and the value you want to initialize it with.
Lastly, while i by itself is a lvalue the expression &i is not an lvalue, because you can't apply the address-of operator to it (i.e you can't do &&i).
Here we have two lvalues i and j
Yep
when i is assigned to j it becomes an implicit rvalue because a copy of i is stored in j
Not really, i is still an lvalue, but it's converted to an rvalue to read its value. This is called an lvalue-to-rvalue conversion. j is still an lvalue.
Would both j and &i be lvalues because they are both physical addresses in memory?
j is an lvalue, but &i is an rvalue; specifically a prvalue of type int*.
Being an lvalue or an rvalue is a property of an expression. Generally, all expressions which constitute a non-const qualified identifier are modifiable lvalues:
int i = 5;
i; // the expression "i" is an lvalue and is modifiable
const int j = 3;
j; // the expression "j" is still an lvalue, but not modifiable
An lvalue expression (unless qualified with const) can be modified through any of the assignment, ++ or -- operators. You can also apply the & "address-of" operator on such an expression.
Some operators like the unary *, the array subscript operator [], and the . and -> operators also yield lvalues. This means that you can say, for example, *p = 3, or a[i] = 5, or b.c++ or &c->d.
On the other hand, expressions which are not lvalues are rvalues (they are temporary and cannot be modified). If you write something like 3 = 5 or 7++, the compiler will complain that the 3 and 7 subexpressions are not lvalues.
The prefix operators return the object
itself as an lvalue. The postfix operators return a copy of the object’s original value
as an rvalue.
so in a statement like so *a++ a is being incremented and a copy of the original value of a is returned as rvalue but from the microsoft c++ language reference on Lvalues and Rvalues
An rvalue is a temporary value that does not persist beyond the expression that uses it
and gives an example
// lvalues_and_rvalues1.cpp
// compile with: /EHsc
#include <iostream>
using namespace std;
int main()
{
int x = 3 + 4;
cout << x << endl;
}
In this example, x is an lvalue because it persists beyond the expression that defines it. The expression 3 + 4 is an rvalue because it evaluates to a temporary value that does not persist beyond the expression that defines it.
My questions:
1) what is the rvalue being returned from the *a++ so that it can be dereferenced?
2) Did i misunderstand any concept ?
Thanks in advance!
The prefix operators return the object itself as an lvalue. The postfix operators return a copy of the object’s original value as an rvalue.
Wrong! Well, mostly. If the quote is talking about all prefix/suffix operators, then it's completely errated. However, if it's talking about the ++ and -- prefix/postfix pairs, then it's correct.
Now, taking that into account...
what is the rvalue returning from the *a++ so that it can be dereferenced?
Assuming a is a pointer of some kind, a++ increments a and yields a rvalue consisting of a's value before the increment. The increment and decrement operators, ++ and --, in both postfix and prefix forms, require an lvalue as their operator. This is because rvalues are temporary, that is, their scope is limited by the expression their occur in, so these operators make little or no sense on them. Remember, these operators not only inspect/read, but change/write to the variable itself.
The unary * operator takes a pointer(-like) object and dereferences it, yielding an lvalue found in there. It works for both rvalue and lvalue pointers. This is because * can be considered sort of a "passive" operator. It does not change/write to the pointer itself, but dereferences it and returns the lvalue object at the address stored by the pointer, whose address is of course that contained by the pointer. As all that * needs is the memory address contained in a pointer object, and the address of the pointer itself, if it has one at all, is useless here, * makes sense for both rvalues and lvalues.
You can think that * "requires an rvalue", and that "lvalues can be used as rvalues when necessary", if it clarifies (or confuses?) things a little bit more.
*a++ is equivalent to:
auto temp = *a;
a++;
// Use the value of temp here
except you can only refer to the value once, where as temp you could refer to multiple times.
This question already has answers here:
Why ++i++ gives "L-value required error" in C? [duplicate]
(5 answers)
Closed 9 years ago.
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.
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.
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:
Postfix Operand Doc.
Prefix Operand Doc.