C++ CPU寄存器用法

Joh*_*nes 10 c++ compiler-construction assembly mips cpu-registers

在C++中,局部变量总是在堆栈上分配.堆栈是应用程序可以占用的允许内存的一部分.该内存保存在RAM中(如果没有换成磁盘).现在,C++编译器是否总是创建在堆栈中存储局部变量的汇编程序代码?

举例来说,以下简单代码:

int foo( int n ) {
   return ++n;
}
Run Code Online (Sandbox Code Playgroud)

在MIPS汇编程序代码中,这可能如下所示:

foo:
addi $v0, $a0, 1
jr $ra
Run Code Online (Sandbox Code Playgroud)

如您所见,我根本不需要使用堆栈.C++编译器会识别出来,并直接使用CPU的寄存器吗?

编辑:哇,非常感谢您几乎立即和广泛的答案!foo的功能主体当然应该是return ++n;,而不是return n++;.:)

jal*_*alf 12

是.没有规则"变量总是在堆栈上分配".C++标准没有说明堆栈.它不假设堆栈存在,或存在寄存器.它只是说代码应该如何表现,而不是如何实现.

编译器只在必要时将变量存储在堆栈中 - 例如,当它们必须通过函数调用时,或者如果您尝试获取它们的地址.

编译器不是傻瓜.;)


int*_*nt3 9

免责声明:我不知道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;
}
Run Code Online (Sandbox Code Playgroud)

编译以上内容g++ -O3 -fomit-frame-pointer -c test.cpp,我得到foo1:

mov eax,DWORD PTR [esp+0x4]
add eax,0x1
ret
Run Code Online (Sandbox Code Playgroud)

如您所见,它从堆栈中读取值.

这是foo2:

lea eax,[ecx+0x1]
ret
Run Code Online (Sandbox Code Playgroud)

现在它直接从寄存器中获取值.

当然,如果您内联函数,编译器将在较大函数的主体中进行简单的添加,而不管您指定的调用约定.但是当你无法内联时,这将会发生.

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

编辑1:如果您正在讨论普通的局部变量(不是函数参数),那么编译器会在它认为合适的情况下将它们分配到寄存器或堆栈中.

编辑2:看起来调用约定是特定于体系结构的,MIPS将传递堆栈上的前四个参数,正如Richard Pennington在他的回答中所述.因此,在您的情况下,您不必指定额外属性(实际上是x86特定的属性.)


Joh*_*iss 8

是的,一个好的,优化的C/C++将优化它.甚至MUCH更多:在这里看到:费利克斯·冯·Leitners编译调查.

普通的C/C++编译器无论如何都不会将每个变量放在堆栈上.您的foo()函数的问题可能是变量可以通过堆栈传递给函数(系统的ABI(硬件/ OS)定义).

使用C的register关键字,您可以给编译器一个提示,即将变量存储在寄存器中可能会很好.样品:

register int x = 10;
Run Code Online (Sandbox Code Playgroud)

但请记住:x如果想要,编译器可以免费存储在寄存器中!


Ric*_*ton 6

答案是肯定的,也许吧.它取决于编译器,优化级别和目标处理器.

在mips的情况下,前四个参数(如果很小)在寄存器中传递,返回值在寄存器中返回.因此,您的示例无需在堆栈上分配任何内容.

实际上,真相比小说更奇怪.在您的情况下,参数返回不变:返回的值是++运算符之前的n:

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

    addu    $2, $zero, $4
    jr      $ra
    nop
Run Code Online (Sandbox Code Playgroud)