C++ C++;在Linux/x86-84上传递大对象的调用约定
我试图理解在C++/Linux/x86-64平台中,通过值传递对象作为函数参数的开销 我用于探索的实验代码发布在下面和godbolt.org上: 假设函数是一元函数。我观察到的是:C++ C++;在Linux/x86-84上传递大对象的调用约定,c++,linux,assembly,x86-64,calling-convention,C++,Linux,Assembly,X86 64,Calling Convention,我试图理解在C++/Linux/x86-64平台中,通过值传递对象作为函数参数的开销 我用于探索的实验代码发布在下面和godbolt.org上: 假设函数是一元函数。我观察到的是: 如果参数对象的大小为8字节,则将其放入RDI中 如果参数的大小为16字节(每个8字节包含两个子对象),则这两个子对象将放入RDI和RSI 如果参数大于16字节,将通过堆栈传递 我只考虑整型和指针以及这些基本类型的组成类型。我知道传球花球/双打是不同的 std::function的大小为32字节(GCC/Linux实现
std::function
的大小为32字节(GCC/Linux实现,long+long+pointer+pointer=32字节)。因此,按值传递std::function
应该类似于我的代码中定义的passstruct Person4
。但是输出程序集显示passstd::function
与passstruct Person3
非常不同。看起来std::函数是通过指针传递的,对吗?为什么会有这样的差异
#include <functional>
struct Person0 {
long name;
};
long GetName(Person0 p) {
return p.name;
}
struct Person1 {
long name;
long age;
};
long GetName(Person1 p) {
return p.name;
}
struct Person2 {
long name;
long age;
long height;
};
long GetName(Person2 p) {
return p.name;
}
struct Person3 {
long name;
long age;
long height;
long weight;
};
long GetName(Person3 p) {
return p.name + sizeof(p);
}
long Invoke(std::function<long(long)> f) {
return f(20) + sizeof(f);
}
int main() {
Person3 p;
p.name = 13;
p.age = 23;
p.height = 33;
p.weight = 43;
long n = GetName(p);
std::function<long(long)> ff;
Invoke(ff);
return 0;
}
#包括
结构Person0{
长名称;
};
长GetName(Person0 p){
返回p.name;
}
结构人1{
长名称;
年龄长;
};
长GetName(person1p){
返回p.name;
}
结构人2{
长名称;
年龄长;
高;
};
长GetName(person2p){
返回p.name;
}
结构人3{
长名称;
年龄长;
高;
长重;
};
长GetName(Person3 p){
返回p.name+sizeof(p);
}
长调用(std::函数f){
返回f(20)+sizeof(f);
}
int main(){
人3p;
p、 姓名=13;
p、 年龄=23岁;
p、 高度=33;
p、 重量=43;
长n=GetName(p);
std::函数ff;
调用(ff);
返回0;
}
您要阅读的文档是,特别是第3.2.3节
«参数通过»
大于32字节的结构,总是放在堆栈上。
对于您描述的结构,引用的是
struct Person4
,但您的代码中没有。是否是std::function
的类型擦除使编译器执行此操作?(可能只是增加了混淆-有趣的问题)@Peter struct Person4应该是struct Person3,谢谢你指出这一点。TL:DR:在SSE/SSEUP的东西上,是一个结构或其他对象,由所有float
/双成员组成(例如\u m128
)如果大小合适,可以使用XMM或YMM reg;否则,它就像任何物体一样。是的,最后一个能做到。事实上,如果您向Person3
添加复制构造函数或析构函数,则其行为与std::function
相同。非常感谢您的解释。