在C++中,为什么有些编译器拒绝将只包含double的对象放入寄存器?

Ari*_*ler 16 c++ compiler-specific

在Scott Meyer的Effective C++第20节中,他指出:

一些编译器拒绝将仅包含double的对象放入寄存器中

当按值传递内置类型时,编译器会很乐意将数据放入寄存器并快速发送ints/ doubles/ floats/等.沿.但是,并非所有编译器都会以相同的宽限度处理小对象.我可以很容易地理解为什么编译器会以不同的方式处理对象 - 按值传递Object比在vtable和所有构造函数之间复制数据成员要多得多.

但仍然.对于现代编译器来说,这似乎是一个容易解决的问题:"这个类很小,也许我可以区别对待".Meyer的声明似乎暗示编译器将对仅由int(或charshort)组成的对象进行优化.

有人可以进一步了解为什么有时这种优化不会发生?

P.W*_*P.W 14

我在网上找到了" 调用不同C++编译器和操作系统的约定 "(在2018-04-25更新),其中有一个描述"传递结构,类和联合对象的方法"的表.

从表中可以看到,如果一个对象包含long double,整个对象的副本将转移到此处显示的所有编译器的堆栈.

在此输入图像描述

也来自同一资源(重点增加):

如果参数是结构,类或联合对象,则有几种不同的方法将参数传递给函数.始终创建对象的副本,并将此副本传送到寄存器,堆栈或指针上的被调用函数,如表6中所指定.表中的符号指定要使用的方法.S优先于I和R.PI和PS优先于所有其他传递方法.

如表6所示,如果对象太大或太复杂,则无法在寄存器中传输.例如,具有复制构造函数的对象无法在寄存器中传输,因为复制构造函数需要该对象的地址.复制构造函数由调用者调用,而不是被调用者.

即使需要更高的对齐,在堆栈上传递的对象也按堆栈字大小对齐.即使明确请求对齐,由指针传递的对象也不会被所研究的任何编译器对齐.64位Windows ABI要求指针传递的对象与16对齐.

数组不被视为对象而是被视为指针,并且不会创建数组的副本,除非数组被包装到结构,类或联合中.

Linux的64位编译器在以下方面与ABI(版本0.97)不同:具有继承,成员函数或构造函数的对象可以在寄存器中传递.具有复制构造函数,析构函数或虚拟对象的对象通过指针而不是堆栈传递.

适用于Windows的英特尔编译器与Microsoft兼容.Linux的英特尔编译器与Gnu兼容.