在C ++中,本地变量总是分配在栈上。栈是允许的内存,你的应用程序能够占据的一部分。该内存保存在您的RAM(如果没有交换到磁盘)。现在,做一个C ++编译器总是创建存储在栈上的局部变量的汇编代码?

举个例子,下面的简单的代码:

int foo( int n ) {
   return ++n;
}

在MIPS汇编代码,这可能是这样的:

foo:
addi $v0, $a0, 1
jr $ra

正如你所看到的,我并不需要在所有使用堆栈代替n。将C ++编译器识别,并直接使用该CPU的寄存器?

编辑:哇,非常感谢您几乎是即时的和广泛的答案! foo的函数体当然应该return ++n;,不return n++;。 :)

有帮助吗?

解决方案

免责声明:我不知道MIPS,但我知道有些X86,我认为原则应该是一样的..

在通常的函数调用约定,编译器将n的值推送到堆栈上以将其传递给函数foo。然而,有fastcall约定,您可以使用来告诉GCC通过寄存器传递值来代替。 (MSVC也有这个选项,但我不知道它的语法是什么。)

test.cpp:

int foo1 (int n) { return ++n; }
int foo2 (int n) __attribute__((fastcall));
int foo2 (int n) {
    return ++n;
}

编译上面g++ -O3 -fomit-frame-pointer -c test.cpp,我获得foo1

mov eax,DWORD PTR [esp+0x4]
add eax,0x1
ret

可以看到,它读取在从堆栈的值。

和这里的foo2

lea eax,[ecx+0x1]
ret

现在它直接从寄存器取值。

当然,如果你内联函数,编译器会做一个简单的加法在较大的函数体,无论调用约定的指定。但是,当你不能得到它内联,这会发生。

2免责声明:我不是说你应该不断地在事后的编译器。这可能是在大多数情况下,实际的和必要的。但不要以为它产生完美的代码。

修改1:如果你正在谈论普通本地变量(未函数参数),然后是,编译器将在寄存器或其认为合适的栈上分配它们

修改2:的看来,调用约定是体系结构特异性的,和MIPS将通过在堆栈上的前四个参数,如理查德宁顿在他的回答已表示。所以你的情况,你不必指定额外的属性(这实际上是一个特定的x86属性。)

其他提示

是。没有规则“变量总是在堆栈上分配”。 C ++标准没有提到一个stack.It不认为一个堆栈中存在,或寄存器存在。它只是说,代码应该如何表现,它不应该如何实现。

在编译器只存储在堆栈变量时,它必须 - 当他们不得不忍受过去的函数调用,例如,或者如果你试图把他们的地址

编译器并不笨。 ;)

是,一个良好的,优化的C / C ++将优化这一点。即使的 MUCH 的更多:在这里看到:费利克斯·冯·Leitners编译调查

一个普通的C / C ++编译器不会把每一个变量在堆栈上了。与您foo()功能的问题可能是可变可以得到通过堆栈的函数(你的系统的ABI(硬件/ OS),定义了)通过。

在C的register关键字,您可以给编译器的提示的,这可能会是很好的一个变量保存在寄存器中。样品:

register int x = 10;

但要记住:编译器是免费不保存x在寄存器中,如果要

答案是肯定的,也许。它依赖于编译器,优化级,和所述目标处理器。

在MIPS的情况下,前四个参数中,如果小,在寄存器传递和返回值被在寄存器返回。所以,你的例子有没有要求分配堆栈上的任何东西。

其实,真理比小说还离奇。在你的情况的参数原样返回:返回的值是n的++运算符之前:

foo:
    .frame  $sp,0,$ra
    .mask   0x00000000,0
    .fmask  0x00000000,0

    addu    $2, $zero, $4
    jr      $ra
    nop

由于您的例子foo功能是标识功能(它只是返回它的参数),我的C ++编译器(VS 2008)完全消除此函数调用。如果我将其更改为:

int foo( int n ) {
   return ++n;
}

,编译器内联这个与

lea edx, [eax+1] 

是,这些寄存器在C中使用++。的MDR(存储器数据寄存器)中包含的数据被获取并存储。例如,检索单元123的内容,我们将加载值123(二进制)插入MAR并执行提取操作。当操作完成后,细胞123的内容的副本将在MDR。到值98存储到小区4中,我们加载一个4到MAR和一个98到MDR和执行存储。当操作完成单元4的内容将被设置为98,通过丢弃不管在那里以前。数据和地址寄存器与他们合作来实现这一目标。在C ++中也一样,当我们初始化一个变种具有值或询问它的值,同样的现象发生的情况。

和,还有一两件事,现代编译器也进行寄存器分配,这是有点超过存储器分配得更快。

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