Xia*_*Guo 5 c++ linux assembly x86-64 calling-convention
我试图了解在 C++/Linux/x86-64 平台中按值传递对象作为函数参数的开销。
我用于探索的实验代码发布在下面和 Godbolt.org 上:https ://godbolt.org/z/r9Yfv4
假设函数是一元的。我观察到的是:
我只考虑整型和指针以及这些基本类型的组合类型。我知道传递浮动/双打是不同的。
的大小std::function
为 32 字节(GCC/Linux 实现,long + long + 指针 + 指针 = 32 字节。)。所以std::function
按值传递应该看起来像struct Person4
在我的代码中定义的传递。但是输出程序集显示 passstd::function
与 pass 非常不同struct Person3
。看起来 std::function 是通过指针传递的,对吗?为什么会有这样的差异?
#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;
}
Run Code Online (Sandbox Code Playgroud)
您要阅读的文档是System V ABI for x86-64,特别是第 3.2.3\n\xc2\xabParamater Passing\xc2\xbb 节
\n> 32 字节的结构始终位于堆栈中。\n对于 <= 32 字节的结构,存在一些逻辑:
\n\n合并后清理表示,鉴于大小大于 2 个八字节(16 字节),并且第一个参数不是 SSE,或者任何其他参数不是 SSEUP,整个聚合将被归类为 MEMORY(堆栈)。
\n关于 的使用std::function
,最后一条规则可以解释它:
\n\n\n
\n- 如果 C++ 对象具有非平凡的复制构造函数或非平凡的析构函数,则它通过不可见引用传递(该对象在参数列表中被具有类\nINTEGER 的指针替换)
\n