为什么在不使用堆栈内存时分配堆栈内存?


14

考虑以下示例:

struct vector {
    int  size() const;
    bool empty() const;
};

bool vector::empty() const
{
    return size() == 0;
}

生成的汇编代码vector::empty(通过clang,带有优化):

push    rax
call    vector::size() const
test    eax, eax
sete    al
pop     rcx
ret

为什么要分配堆栈空间?完全不使用。该pushpop可以省略。优化的MSVC和gcc构建也为此功能使用了堆栈空间(请参阅godbolt),因此必须有一个原因。


7
您是否考虑了隐式this参数?
dan04

1
@Bob__:不,我为什么要?vector::size()在示例中未定义来模拟未内联。
Gut博士

1
那么,编译器如何优化它不知道的东西?
Bob__

1
@Bob__:我认为,了解的实现vector::size()与为分配或不分配堆栈框架无关vector::empty()empty()无论它是什么,在其中都被称为。
Gut博士

1
好吧,您正在调用一个返回某些内容的函数,因此您需要空间(如果您不知道更好的话)。
Bob__

Answers:


11

它分配堆栈空间,因此堆栈是16字节对齐的。这是必需的,因为返回地址占用8个字节,因此需要额外的8个字节的空间来保持堆栈16个字节的对齐。

对于某些编译器,可以使用命令行参数来配置堆栈框架的对齐方式。

  • MSVC文档说堆栈始终是16字节对齐的。没有命令行参数可以更改此设置。Godbolt示例显示rsp在该函数的开头减去了40个字节,这意味着其他因素也会对此产生影响。
  • clang:该-mstack-alignment选项指定堆栈对齐方式。似乎默认值为16,尽管没有记录。如果将其设置为8,则堆栈分配(pushpop)从生成的汇编代码中消失。
  • gcc:该-mpreferred-stack-boundary选项指定堆栈对齐方式。如果给定值为N,则表示2 ^ N个对齐字节。默认值为4,表示16个字节。如果将其设置为3(即8个字节),则堆栈分配(subaddfor rsp)从生成的汇编代码中消失。

查看godbolt


这就是为什么c ++专家会一直警告:将struct / class成员按最长/最大大小的顺序减小到最小的方式...只有这样,它才能正确有效
Nonock

@geza:谢谢。我对其他两个编译器进行了一些研究,并将其写入您的答案。你喜欢它吗?
Gut博士

1
@ Dr.Gut:谢谢,您的回答更好,更完整了。注意,堆栈对齐通常在系统的ABI中记录(例如,对于某些系统,这是文档:github.com/hjl-tools/x86-psABI/wiki/X86-psABI)。
geza

@geza:谢谢。
Gut博士
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.