tags:

views:

224

answers:

7

in C, i have this code piece:

int a;
a = 10 + 5 - 3

I want to ask: where is (10+5-3) stored at? (As far as I know, a is located on stack, how about (10+5-3)? How does this rvalue get calculated?)

+3  A: 

Typically, the r-value is "stored" within the program itself.

In other words, the compiler itself (before the program is ever run) computes the 10 + 5 - 3 value (it can do so since since it is all based on constant immediate values), and it emits the assembly code to store the result of this calculation in whatever l-value for the assignement (in this case, the variable named a, which the compiler probably knows as a relative address to a data segment origin of sorts).

The r-value, which has a value of 12 is therefore only found inside the binary of the program, within a assembly instruction that looks like

  mov <some dest, typically DS-relative>, $0C

$0C is the "r-value".

If the r-value happened to be the result of a calculation that can only done at run-time, say if the underlying c code was: a = 17 * x; // x some run time var, the r-value would too be "stored" (or rather materialized) as a series of instructions within the program binary. The difference with the simple "mov dest, imm" above is that it would take several instructions to load the variable x in an accumulator, multiply by 17 and store the result at the address where the variable a is. It is possible that the compiler may "authorize itself" ;-) to use the stack for some intermediate result etc. but such would be
a) completely compiler dependent
b) transiant
c) and typically would only involve part of the r-value
it is therefore safe to say that the r-value is a compile-time concept which is encapsulated in parts of the program (not the data), and isn't stored anywhere but in the program binary.

In response to paxdiablo: the explanation offered above is indeed restrictive of the possibilities because the c standard effectively does not dictate anything of that nature. Never the less, most any r-value is eventually materialized, at least in part, by some instructions which sets things up so that the proper value, whether calculated (at run time) or immediate gets addressed properly.

mjv
I think he's asking where are the different parts of the code located in the stack.
Derek B.
*Nothing* in the C standard mandates this behavior. You should say: "Typically, the r-value is ...".
paxdiablo
@paxdiablo. Agreed and edited with "Typically, " I also added a small paragraph at the bottom, do you concur with it ?
mjv
Yes, +1 from me.
paxdiablo
+1  A: 

This is compiler dependent. Usually the value (12) will be calculated by the compiler. It is then stored in the code, typically as part of a load/move immediate assembly instruction.

Steve Fallows
So you mean (10+5-3) is calculated during compile time? I wonder how the compiler calculate this?
tsubasa
This is a good answer. Implicit in this answer: the expression "10+5-3" is temporarily stored in the working memory of the compiler, probably as an "expression tree" data structure. Then compiler optimizations (in this case, constant propagation) will 'solve' the expression tree where it has constant values. The compiler will result with a "12" and that 12 will be the operand to one of the assembly-language instructions of the program.
Heath Hunnicutt
Heath Hunnicutt
+4  A: 

Constants are probably simplified at compile time, so your question as literally posed may not help. But something like, say, i - j + k that does need to be computed at runtime from some variables, may be "stored" wherever the compiler likes, depending on the CPU architecture: the compiler will typically try to do its best to use registers, e.g.

 LOAD AX, i
 SUB AX, j
 ADD AX, k

to compute such an expression "storing" it in the accumulator register AX, before assigning it to some memory location with STORE AX, dest or the like. I'd be pretty surprised if a modern optimizing compiler on an even semi-decent CPU architecture (yeah, x86 included!-) needed to spill registers to memory for any reasonably simple expression!

Alex Martelli
I deleted my answer, so you might want to take out "GMan says". :)
GMan
A: 
  • The result of the computation in the RHS (right-hand-side) is computed by the compiler in a step that's called "constant propagation".
  • Then, it is stored as an operand of the assembly instruction moving the value into a

Here's a disassembly from MSVC:

  int a;
  a = 10 + 5 - 3;

0041338E  mov         dword ptr [a],0Ch
Eli Bendersky
+1  A: 

Where it stores it is actually totally up to the compiler. The standard does not dictate this behavior.

A typical place can be seen by actually compiling the code and looking at the assembler output:

int main (int argc, char *argv[]) {
    int a;
    a = 10 + 5 - 3;
    return 0;
}

which produces:

        .file   "qq.c"
        .def    ___main;
            .scl    2;
            .type   32;
        .endef
        .text
.globl _main
        .def    _main;
            .scl    2;
            .type   32;
        .endef
_main:
        pushl   %ebp
        movl    %esp, %ebp
        subl    $8, %esp
        andl    $-16, %esp
        movl    $0, %eax
        addl    $15, %eax
        addl    $15, %eax
        shrl    $4, %eax
        sall    $4, %eax
        movl    %eax, -8(%ebp)
        movl    -8(%ebp), %eax
        call    __alloca
        call    ___main
        movl    $12, -4(%ebp)         ;*****
        movl    $0, %eax
        leave
        ret

The relevant bit is marked ;***** and you can see that the value is created by the compiler and just inserted directly into a mov type instruction.

Note that it's only this simple because the expression is a constant value. As soon as you introduce non-constant values (like variables), the code becomes a little more complicated. That's because you have to look those variables up in memory (or they may already be in a register) and then manipulate the values at run-time, not compile-time.

As to how the compiler calculates what the value should be, that's to do with expression evaluation and is a whole other question :-)

paxdiablo
Good example. I was going to say "look at the assembly generated" but I was too lazy to create an example. :) Note also, it can become more complicated if the constant value is larger. Some processors have a limit (e.g. 8 bits or 16 bits) on how large a value can be put directly into an instruction.
Steve Fallows
A: 

Your question is based on an incorrect premise.

The defining property of lvalue in C is that it has a place in storage, i.e it is stored. This is what differentiates lvalue from rvalue. Rvalue is not stored anywhere. That's what makes it an rvalue. If it were stored, it would be lvalue by definition.

AndreyT
It has to be stored *somewhere* otherwise you can't use it :-)
paxdiablo
No, it doesn't. For example, when you initialize a variable with `0`, the machine code might just `xor` a register with itself. Is `0` "stored somewhere" in this case? No. A `1` can be generated as an increment of previously zeroed register. And so on. Rvalues don't have to be stored anywhere. That's what makes them rvalues.
AndreyT
A: 

The terms "lvalue" and "rvalue" are used to bisect the world of expressions. That is, (10+5-3) is an expression that happens to be an rvalue (because you cannot apply the & operator to it -- in C++ the rules are more complicated). At runtime, there are no expressions, lvalues or rvalues. In particular, they aren't stored anywhere.

You were wondering where the value 12 was stored, but the value 12 is neither an lvalue nor an rvalue (as opposed to the expression 12 which would be an rvalue, but 12 does not appear in your program).

Fred