0

Consider this code:

int x = 99;
int * p = &x;
*p = *p + 1;

Why do the *p on the left side and right side of the = operator differ?

How does the compiler know to use the left *p to be the object x and the right *p to be the value of x?

Specifically, if the compiler evaluates *p to be the value of x, why does the *p on the left side not evaluate to 99, creating an erroneous assignment to a literal: 99 = 99 + 1;?
Similarly, if the compiler evalues *p to be the object x (assuming that that is what the left operand of the = operator expects), why does not the *p on the right hand side also evaluate to the object x?

  • 2
    C or C++? Choose one, they're different languages. Moreover, in `*p` you're dereferencing `p`. This is the very basic of C++, refer to a [good C++ book](https://stackoverflow.com/questions/388242/the-definitive-c-book-guide-and-list) – Jason Jul 23 '22 at 14:53
  • 1
    `*p` is not the address of `x`. – Barmar Jul 23 '22 at 14:54
  • You're assuming that "value" and "type" are the only properties of an expression, but they are not. There are also "value category" (`*p` is lvalue so it's allowed here, `99` is prvalue and it's not), and "address". – HolyBlackCat Jul 23 '22 at 14:55
  • 2
    This is no different from `x = x + 1` – Barmar Jul 23 '22 at 14:55
  • There is no "literal" in your code, other than the `99` that is used to initialize the `x` **variable**. – Adrian Mole Jul 23 '22 at 14:55
  • 6
    ... if you're teaching C or C++ and don't understand what's happening in this code, then I don't think there's much than anyone on S.O. can do (politely) to help you. – Adrian Mole Jul 23 '22 at 14:57
  • @Barmar I'll try again with `x=x+1` how does the compiler knows to give 99 AND 1 as arguments for the + operator. But to give the address of x as the first argument to the = operator? – forstack overflowizi Jul 23 '22 at 14:58
  • 3
    `*p` is an [_lvalue expression_](https://en.cppreference.com/w/cpp/language/value_category). It is being used on both sides of an assignment operator. On the left it's being written, and on the right it's being read. – paddy Jul 23 '22 at 14:59
  • 1
    @AdrianMole Of course i understand what happens in this code.. read my question again. I am trying to explain to a student how the compiler knows to evaluate differently the same expression. what is the set of rules that defines when an expression is evaluated to an integer, and when it is evaluated to the be the address of the variable (to be written to) – forstack overflowizi Jul 23 '22 at 15:02
  • 1
    No offence, but if you can't clearly explain something to someone, then you don't understand it. Even in this very comment, you're saying that there's some difference between the two `*p`, but there's none. – HolyBlackCat Jul 23 '22 at 15:05
  • 1
    I think it's fair to expect a teacher to have a deeper understanding of the language than what is being demonstrated here. That said, your student asked a good question that was beyond you, and this is a learning experience for _you_. – paddy Jul 23 '22 at 15:08
  • Answer to Q1: they don't differ. Q2: the question is based on a false premise. Q3. the question is also based on a false premise. Q4. the question is based on a false premise. – Eljay Jul 23 '22 at 15:41

2 Answers2

7

The result of the dereference operator * is an lvalue. It references an object (not just a value) that can be assigned to.

This means that *p is an lvalue denoting the object that p points to, specifically x.

When an lvalue is used in an expression such as *p + 1 or x + 1, the lvalue is converted to a value and is no longer an lvalue. This conversion does not happen when the lvalue is the left operand of the assignment operator.

This conversion is detailed in section 6.3.2.1p2 of the C standard:

Except when it is the operand of the sizeof operator, the _Alignof 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); this is called lvalue conversion

So the expression *p = *p + 1 is effectively the same as *p = 99 + 1. The same goes for x = x + 1.

dbush
  • 205,898
  • 23
  • 218
  • 273
  • 1
    This quote is pure gold – forstack overflowizi Jul 23 '22 at 15:22
  • I've closed this question as a duplicate (because I think it is); however, your answer here would be very valuable (IMHO) as an answer to the linked dupe. – Adrian Mole Jul 23 '22 at 15:42
  • 1
    @AdrianMole Isn't it better to use the question with better answers as the duplicate target? – Unmitigated Jul 23 '22 at 15:49
  • 1
    @Unmitigated Possibly. Or maybe a merge would be in order? I've just asked about that in the [SOCVR](https://chat.stackoverflow.com/transcript/message/54961642#54961642) chat-room. – Adrian Mole Jul 23 '22 at 15:51
  • @Unmitigated The 'original' is not a *bad* question and it also has some decent answers. I wouldn't want any/either to be 'lost' to the wider community. – Adrian Mole Jul 23 '22 at 15:55
2

C and C++, like many languages, distinguish between L-values and R-values. These terms refer to the way an expression is treated when it's on the left or right side of an assignment.

There are a number of intricacies, but for the purpose of answering your question simply, an L-value refers to a location, while an R-value is any general value (like the amount in a numeric type, or all the contents of a structure).

So when you write:

L-value = R-value

it means to copy the R-value into the location described by the L-value.

The simplest case is an ordinary variable assignment:

x = x + 1;

On the right side, x is an R-value; we get the number 99 from it, add 1 to that, producing the value 100. On the left side, x is an L-value that refers to the memory address of the variable, and we store 100 in that location.

It's no different when you replace x with *p.

Barmar
  • 741,623
  • 53
  • 500
  • 612