Search code examples
cexpressionlvaluervalue

Return the kind of an expression in C, i.e., whether it's an rvalue or lvalue


Can I print how an expression is being evaluated?

For example if I wanted to find out whether a value was being evaluated as an rvalue or lvalue I'd call the hypothetical code:

int main() {
    if(isrvalue(*(int *)4)) return 0;
    else return 1;
}

This creates problems as we're discovering below that the 'type' of an expression can depend on whether it's on the right or left side of the assignment operator. So the test would be more suited as

supports_lvalue(*(int *)4)

Although again this is only hypothetical and may be left to just playing around with basic examples.

The reason is only for experimentation but it might be useful in debugging if it's possible.


Solution

  • According to the C Standard, section 6.3.2.1:

    An lvalue is an expression (with an object type other than void) that potentially designates an object.

    Although this is rather vague, it continues with

    The name ‘‘lvalue’’ comes originally from the assignment expression E1 = E2, in which the left operand E1 is required to be a (modifiable) lvalue.

    And further more

    What is sometimes called ‘‘rvalue’’ is in this International Standard described as the ‘‘value of an expression’’.

    What this means to me is

    An lvalue is a value that supports assignment and is on the left side of the assignment operator.

    An rvalue is any value not on the left hand side of the assignment operator.

    So for example

    #include <stdio.h>
    
    int main() {
        int array[1], *pointer, i = 42;
        //                      ^    ^-rvalue
        //                    lvalue
    
        *array = i;
        // ^     ^-rvalue
        //lvalue
    
        pointer = array;
        // ^         ^-rvalue
        //lvalue
    
        printf("%p\t%d\n", pointer, *pointer);
        //                    ^-rvalues-^
    
        // causes segfault but compiles:
        *(int *)4 = 2;
        //      ^   ^-rvalue
        //   lvalue
    
        return 0;
    }
    

    As above in the comments and to answer the question fully

    You'd have to use a compiler that lets you access the AST of a given compilation unit.