-1

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.

J. Doe
  • 85
  • 7
  • 2
    This question is rather unclear in my opinion (I really could not understand what you ask). Was about to downvote but as you ask why you get downvotes, I prefere to explain. – Serge Ballesta Jun 11 '16 at 08:11
  • 4
    I don't think there's a way to do it in C. You'd have to use a compiler that lets you access the AST of a given compilation unit. Still, knowing this information *for debugging purposes* would probably be less useful than you might think. A program that uses an rvalue in place of an lvalue won't compile anyway. – Theodoros Chatzigiannakis Jun 11 '16 at 08:32
  • What do you mean by "a value was being evaluated as an rvalue or lvalue". Maybe you ask when lvalue-to-rvalue conversion is applied , but that just depends on the context. Or did you mean to ask whether an expression is an lvalue or not? – M.M Jun 11 '16 at 14:17
  • See section 6.3.2.1 of the C Standard (too big to paste in a comment) – M.M Jun 11 '16 at 14:38
  • For reference: http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1570.pdf#page=72 – J. Doe Jun 11 '16 at 14:44
  • @M.M "An lvalue is an expression (with an object type other than void) that potentially designates an object" seems rather vague whereas "being assigned to" is much more specific. – J. Doe Jun 11 '16 at 14:48

2 Answers2

2

Lvalue points to a storage location which can be assigned with new values. All variables including const variables are lvalues. Lvalues persist beyond the expression that uses it. On the other hand, an rvalue is a temporary value that does not persist beyond the expression that uses it. Lvalues may appear on the left or right side of assignment operator. But rvalues can never appear on left side of assignment operator.

In short: Lvalues are storage areas and rvalues are Values.

Example:

int main(){

    int i = 10;
    int j = 20;

    int* ip;
    int* jp;


    /*  ip and jp are pointer variables, hence L-VALUES.
        they can appear BOTH sides of = operator.
        as shown below.
    */

    ip = &i;
    jp = &j;
    jp = ip;

    /*  values such as 1, 25, etc are Values, hence R-VALUES
        they can appear only RIGHT side of = operartor
        as shown below, 1 on left causes error not ip
    */

    ip + 1  = &i;  // invalid
    ip = &i + 1;   // valid, however printf("%d", *ip); might print a Garbage value

    /*  *ip and *jp are also L-VALUES, including *(ip + 1) or *(ip + 2)
        they can appear both sides

    */

    *ip = 1 + *jp;

    return 0;
}

You get a compilation error when you incorrectly use lvalues or rvalues.

Ajeet Shah
  • 18,551
  • 8
  • 57
  • 87
  • 1
    @JDoe You said that you can convert an `rvalue` into `lvalue`. This statement is not correct. There is no such conversion. `*p`, `*(p+1)`, `*(p+2)` and `p` are Lvalues. – Ajeet Shah Jun 11 '16 at 10:14
  • You can also check: http://stackoverflow.com/questions/17684476/is-p-an-lvalue-or-rvalue – Ajeet Shah Jun 11 '16 at 10:15
  • p+1 is an rvalue and upon encompassing it with the unary '*' becomes an lvalue. – J. Doe Jun 11 '16 at 10:33
  • I get what you say. But if someone asks you "How to convert a rValue into a lValue?" You can not answer that just encompass it with `*` – Ajeet Shah Jun 11 '16 at 10:35
  • Talking about `p+1`: `p` is lvalue (can appear both sides). and `1` is rvalue (must be on right side). It is `1` which causes error when use use `p+1` on the left side of `=` operator. – Ajeet Shah Jun 11 '16 at 10:39
  • I can compile with the statement `*((int *)0x4) = 2;` – J. Doe Jun 11 '16 at 11:01
  • But try to run this program, it will fail because you are trying to access a memory address which no one is aware about. This memory address might be in use by some other process. – Ajeet Shah Jun 11 '16 at 11:16
  • That's not the point. It's converting an rvalue to an lvalue. – J. Doe Jun 11 '16 at 11:18
  • `0x4` is equal to a number `4`. `(void *)` or `(int *)4` is a memory address value (value, so rvalue). `*((int *)4)` is same as `*p` which is lvalue, it works exactly like a variable. – Ajeet Shah Jun 11 '16 at 11:23
  • 1
    Yes, it may sound crazy. How good are you at `pointer` and memory address concept? If you are good at it. It will be plus to understand this behavior. – Ajeet Shah Jun 11 '16 at 11:28
  • For me it feels like it demystifies everything about pointers and variables. – J. Doe Jun 11 '16 at 11:35
  • Saying lvalues can exist on both sides really makes things more complicated than they should be. For all intents and purposes it should be made clear that lvalues are converted to rvalues when on the right side and vise versa. – J. Doe Jun 11 '16 at 12:42
  • `pointer` and `*pointer` are lvalues, but you label them as "rvalues" – M.M Jun 11 '16 at 14:19
  • @M.M It's being used as an rvalue, is it not? – J. Doe Jun 11 '16 at 14:20
  • I guess you mean they undergo value conversion, but they are still lvalues. Would you say that `4` is a floating point value in the expression `4 + 1.0` ? – M.M Jun 11 '16 at 14:22
  • @M.M Yes. `pointer` and `*pointer` are `lvalues`. Did I write somewhere wrong? – Ajeet Shah Jun 11 '16 at 14:22
  • @Orions the line `printf("%p\t%d\n", pointer, *(pointer));` says `^--rvalues--^` under it – M.M Jun 11 '16 at 14:23
  • the `i` and `array` earlier have the same mistake too – M.M Jun 11 '16 at 14:24
  • @M.M It was an edit by OP as seen in edit history. OP edited the whole example. It seems like OP is still struggling these concepts. – Ajeet Shah Jun 11 '16 at 14:25
  • @M.M I think both of you are struggling. And unless you find a way to correct me other than by stating what you believe I won't change my opinion. – J. Doe Jun 11 '16 at 14:31
  • @Orions I see. I suggest rolling back that edit as it is incorrect and doesn't really resemble what you were saying earlier – M.M Jun 11 '16 at 14:31
  • @J.Doe if you want to post an answer, post an answer, don't radically edit someone else's answer. That's poor etiquette to say the least – M.M Jun 11 '16 at 14:32
  • @M.M How is it poor etiquette? Is the example not totally clear? Why do I need an answer that says the exact same thing with a different example? – J. Doe Jun 11 '16 at 14:33
  • It's not the exact same thing, your edits changed the majority of the answer and made it wrong. – M.M Jun 11 '16 at 14:35
  • @M.M Try again, bucko. – J. Doe Jun 11 '16 at 15:07
0

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.

J. Doe
  • 85
  • 7