在C中,我有这段代码:
int a;
a = 10 + 5 - 3
我想问一下:(10 + 5-3)存放在哪里?
(据我所知,a
位于堆栈上,(10+5-3)
怎么样?如何计算这个右值?)
答案 0 :(得分:5)
常量可能在编译时被简化,因此您提出的问题可能无济于事。但是,确实需要在运行时从某些变量计算的i - j + k
,可以“存储”在编译器喜欢的任何地方,具体取决于CPU架构:编译器通常会尝试尽力使用寄存器,例如
LOAD AX, i
SUB AX, j
ADD AX, k
计算这样的表达式将其“存储”在累加器寄存器AX中,然后将其分配给具有STORE AX, dest
等的某个存储器位置。如果一个现代的优化编译器在一个甚至半体面的CPU架构上(是的,包含x86! - )需要将寄存器溢出到内存中以获得任何相当简单的表达式,我会感到非常惊讶!
答案 1 :(得分:4)
通常,r值“存储”在程序本身内。
换句话说,编译器本身(在程序运行之前 )计算10 + 5 - 3值(它可以这样做,因为它全部基于常量立即值),并且它发出汇编代码以将此计算的结果存储在分配的任何l值中(在这种情况下,名为a的变量,编译器可能知道该变量是数据段原点的相对地址)。 / p>
因此只能在程序的二进制文件中找到值为12的r值,在看起来像
的汇编指令中 mov <some dest, typically DS-relative>, $0C
$ 0C是“r值”。
如果r值碰巧是只能在运行时进行的计算的结果,那么说底层c代码是:a = 17 * x; // x某些运行时间var,r值也将被“存储”(或更确切地说是物化)为程序二进制文件中的一系列指令。上面简单的“mov dest,imm”的区别在于它需要几个指令来将变量x加载到累加器中,乘以17并将结果存储在变量a所在的地址。编译器可能“授权自己”;-)使用堆栈来获得某些中间结果等,但这样可能是
a)完全依赖编译器的
b)传递的
c)并且通常仅涉及r值的部分
因此可以肯定地说,r值是一个编译时概念,它被封装在程序的一部分(而不是数据)中,并且不存储在程序二进制文件中的任何地方。
回应paxdiablo:上面提供的解释确实限制了可能性,因为c标准实际上不决定了那种性质。从来没有,大多数任何r值最终都会实现,至少在某种程度上是通过一些设置的指令来实现的,这样无论是计算(运行时)还是立即计算出的正确值都能得到正确处理。
答案 2 :(得分:1)
这取决于编译器。通常,值(12)将由编译器计算。然后将其存储在代码中,通常作为加载/移动立即汇编指令的一部分。
答案 3 :(得分:1)
它存储的地方实际上完全直到编译器。该标准没有规定这种行为。
通过实际编译代码并查看汇编程序输出,可以看到典型的位置:
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
类型的指令中。
请注意,它只是这么简单,因为表达式是一个常量值。一旦引入非常量值(如变量),代码就会变得有点复杂。那是因为你必须在内存中查找这些变量(或者它们可能已经在寄存器中),然后在运行时而不是编译时中操作值。
关于编译器如何计算值应该是什么,这与表达式评估有关,并且是另一个问题: - )
答案 4 :(得分:0)
a
这是MSVC的反汇编:
int a;
a = 10 + 5 - 3;
0041338E mov dword ptr [a],0Ch
答案 5 :(得分:0)
您的问题基于错误的前提。
C中 lvalue 的定义属性是它在存储中有一个位置,即存储。这是左值与 rvalue 的区别。 Rvalue 不存储在任何地方。这就是它成为右值的原因。如果它被存储,根据定义它将是 lvalue 。
答案 6 :(得分:0)
术语“左值”和“右值”用于将表达式世界二等分。也就是说,(10+5-3)
是恰好是右值的表达式(因为你不能将&amp;运算符应用于它 - 在C ++中,规则更复杂)。在运行时,没有表达式,左值或右值。特别是,它们不会存储在任何地方。
您想知道值12的存储位置,但值12既不是左值也不是右值(与表达式12
相反,后者将是右值,但12
不会出现在你的程序中。)