在C中,我有此代码文章:

int a;
a = 10 + 5 - 3

我想问:(10+5-3)存储在哪里? (我所知道的, a 位于堆栈上,怎么样 (10+5-3)?该rvalue如何计算?)

有帮助吗?

解决方案

通常,R值被“存储”在程序本身中。

换句话说,编译器本身(在程序运行之前)计算10 + 5-3值(可以这样做,因为它都是基于恒定的即时值),并且它发出了汇编代码以将本计算的结果存储在分配的任何l值中(在此,案例,该变量命名为a,编译器可能是对数据段来源的相对地址)。

因此,在程序的二进制中仅发现了一个价值12的R值,该集合指令中 看起来 喜欢

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

$ 0C是“ R-Value”。

如果R-value恰好是只能在运行时完成的计算结果,则说基础C代码是否为:A = 17 * X; // x一些运行时间var,R值也将被“存储”(或更确切地说是实现)作为程序二进制中的一系列说明。上面简单的“ mov dest,imm”的区别在于,将使用几个指令将变量x加载到蓄能器中,乘以17并将结果存储在变量a IS的地址处。编译器可能“授权自身” ;-)将堆栈用于某些中间结果等。但是,这就是
a)完全依赖编译器
b)跨性别者
c)通常只涉及 部分 R-Value
因此,可以肯定地说,r值是一个编译时概念,它封装在程序的部分(不是数据)中,并且在程序二进制中没有存储在任何地方。

响应Paxdiablo:上面提供的解释确实是对可能性的限制,因为C标准有效地确实有效 不是 指示这种性质的任何东西。绝不要少,大多数R值最终至少通过某些说明进行了部分实现,这些说明使事物设置为,以便适当的价值,无论是在运行时还是立即计算得正确。

其他提示

常数可能在编译时简化,因此您提出的问题可能无济于事。但是,例如 i - j + k 确实需要在运行时从某些变量计算出来,无论编译器喜欢的地方都可以“存储”,具体取决于CPU架构:编译器通常会尽力使用寄存器,例如

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

要计算在累加器寄存器AX中“存储”此表达式,然后将其分配给某些内存位置 STORE AX, dest 之类的。如果需要在半决赛的CPU体系结构上进行现代化的优化编译器(是的,包括x86! - ),我会感到非常惊讶。

这是编译器的依赖性。通常,值(12)将由编译器计算。然后将其存储在代码中,通常作为负载/移动立即汇编指令的一部分。

它实际上是在哪里存储 完全 到编译器。该标准不决定这种行为。

一个 典型的 可以通过实际编译代码并查看汇编器输出来查看位置:

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

生产:

        .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

相关位是标记的 ;***** 您可以看到该值是由编译器创建的,只是直接插入 mov 类型说明。

请注意,这只是这个简单的,因为表达式是一个恒定值。一旦您引入非恒定值(例如变量),代码就会变得更加复杂。那是因为您必须在内存中查看这些变量(或者它们可能已经在寄存器中),然后操纵值 运行, , 不是 编译时间.

关于编译器如何计算值应该是什么,这与表达评估有关,并且是另一个问题:-)

  • 编译器在称为“恒定传播”的步骤中计算了RHS(右侧)计算的结果。
  • 然后,将其作为装配说明的操作数存储 a

这是MSVC的拆卸:

  int a;
  a = 10 + 5 - 3;

0041338E  mov         dword ptr [a],0Ch 

您的问题是基于不正确的前提。

定义属性 LVALUE 在C中,它在存储中有一个位置,即 存储. 。这就是区分LVALUE rvalue. 。 rvalue是 不是 存储在任何地方。这就是使它成为rvalue的原因。如果存储了,那将是 LVALUE 根据定义。

术语“ lvalue”和“ rvalue”用于表达式世界。那是, (10+5-3) 是恰好是rvalue的表达式(因为您不能将其应用于它 - 在C ++中,规则更为复杂)。在运行时,没有表达式,lvalues或rvalues。特别是,它们没有存储在任何地方。

您想知道该值12存储在哪里,但是值12既不是lvalue也不是rvalue(与表达式相反 12 这将是一个rvalue,但是 12 没有出现在您的程序中)。

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top