arrayscpointersrvaluelvalue

How does the system know about the type of address it is pointing to in case of a rvalue?


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?


Solution

  • 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;
    }