简体   繁体   中英

Casting a pointer as lvalue

Why (int*) p = &x; is not a valid statement? while *(int*) p = &x; is valid statement with no warnings? I know that casting is rvalue , but how the second statement was compiled with no warnings?

(int*) p = &x;

This is not valid because the result of a cast is not an lvalue. It is simply an expression whose type is the type specified in the cast.

*(int*) p = &x;

This is valid because the result of the dereference operator * is an lvalue. Dereferencing a pointer gives you the object the pointer points to.

Intuitively speaking, an lvalue is an expression that means "here's an honest-to-goodness object," while an rvalue is an expression that means "here's a value that isn't an object." (The distinction is a bit murkier than this, but it's a reasonable simplification for now.) That is, an lvalue is a box you can put something in, while an rvalue is just the value in the box.

For example, the expression 137 is an rvalue since it's a pure number, not a box holding a number. If x is a variable, then the expression x is an lvalue because it represents both the box and the number in it, but the expression x + 137 is an rvalue because it just represents a number, not a box holding a number.

How do casts factor into this? Suppose x is an int . Then (float)x is an rvalue because it purely represents a value - specifically, it's "the number you'd get if you took x and did the least awful thing possible to represent it as a float ." It's not a box you can put something in.

That accounts for why

(int *)p = &x;

doesn't work. (int *)p is an rvalue - a pure value, not something you can assign to - and you're trying to treat it like it's a box you can put something in.

On the other hand, the result of a pointer dereference is an lvalue, since it represents "look over there. that's a box you can put something in," So in that sense, you can write

*(int *)p = x;

because that means

  1. Evaluate the expression (int *)p . Okay, we now have a rvalue, and it's a pointer to somewhere in memory that holds an int .
  2. Dereference that pointer to get *(int *)p . Okay, we now have an lvalue, representing that integer.
  3. Stuff x into that spot. That's fine - *(int *)p is a box.

There may be some other issues, though, with this code:

*(int *)p = &x;

Here, the RHS of this expression has type (int *) , which is a pointer. The LHS of this expression has type int (you dereferenced a pointer to an integer), so you're converting a pointer into an integer. So that means that there is either a missing cast, or you're doing the Wrong Thing with this code.

The second issue is that

*(int *)p

means "interpret p as though it tells you where in memory an int can be found, then write something there." If p isn't a pointer, this is almost certainly going to crash your code because you'll be writing somewhere randomly in memory. And if p is a pointer, then perhaps it's best to cast &x , rather than p ?

p = (T*) &x;

where T is the type of thing pointed at by p .

Technical terminology can sometimes be confusing, especially when the reader does not understand well how things work.

What is a lvalue? Something that has an address. In the first case you have a pointer. In the second case, you dereference a pointer.

What is a pointer? A pointer is an address. An address does not have an address itself (well, let's not get too technical here). In your example, let's assume p is the constant 1235. What's the address of it? None, it's just a constant, it may not exist in memory. Maybe it's in a register. Maybe the compiler optimized it away completely. More over, your expression is (int*)p = &x saying "take address 1235 and assign to it the address of x, which may be something like 6789". In other words, "change the address 1235 to 6789". What?? Change an address?!

What is a dereferenced pointer? It's the contents of a pointer, ie the value at the address pointed to by the pointer. Now that, by definition, has an address. That's what's happening in the second statement. It's saying "set the contents at the address pointed to by p to &x ". So in my example it says "set the value at the memory address 1235 to 6789". Now that makes sense. This is why it is a lvalue.

I hope it makes sense.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM