开发者

where is rvalue stored in c?

in C, i have this code piece:

开发者_JS百科
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?)


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.


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!


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.


  • 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 


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 :-)


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.


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).

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜