I have some doubt (possibly a misconception) regarding the concept of rvalues when it comes to pre-increment or post-increment. Consider the following C program:
#include <stdio.h>
int main() {
int a[10];
int *ptr = a;
printf("%d", *++ptr);
return 0;
}
Here, in the *++ptr
expression, first ++ptr
is evaluated, which returns the address of a[1]
, which is an rvalue. My question is when we then dereference that rvalue (address) using the *
operator, how does the system know how many bytes of memory to fetch? Because ++ptr
is just an rvalue and there is no way of knowing from an rvalue what type of data it is pointing to (address/constant).
On the contrary, when we do something like *ptr
, then the system knows to take 4 bytes or 2 bytes (depending on the size of int
) because ptr
and *ptr
are both treated as lvalues and the system knows the type of data ptr
is pointing to.
Can you clear my misunderstanding/misconception on this?
An rvalue does have a type – in the case of the prefix (and postfix) increment and decrement operators, that type is the same as the type of the operand. So, if ptr
is declared as int *ptr;
, then the type of the result of ++ptr
is also int*
.
If rvalues did not have types, then array access would be effectively meaningless, because the expression, a[i]
(where a
is an array of type T
) is exactly equivalent to *(a + i)
, where the pointer arithmetic and subsequent dereferencing can only be properly performed if the rvalue result of the a + i
operation maintains the type of the first (in this case) operand (which will be treated as a pointer to the first element of the array, thus a T*
).
There are some 'gotchas' though, when using the results of operation expressions as types. In the following code, we can see that the result type of ++c
is (like c
itself) a char
; however, the result type of c + 1
is an int
(whose size, on my platform, is 4 bytes):
#include <stdio.h>
int main()
{
char c = 42;
printf("%zu %zu %zu\n", sizeof(c), sizeof(++c), sizeof(c + 1)); // Shows: 1 1 4
return 0;
}