按值在C / C ++中传递结构时,必须复制结构内容。编译器如何实现这一目标?即,通常为此副本发出哪些汇编指令?
这些时间有多快,例如与调用memcpy相比?
现在考虑以下代码:
struct X { int i, j, k; };
void foo(X x);
void foo( int i, int j, int k);
调用foo(X)和foo(int,int,int)之间有什么区别,或者生成的汇编代码是否相同(考虑参数的传递)?
答案 0 :(得分:5)
编译器如何实现这一目标?
他们为该类/结构调用复制构造函数。如果您不提供一个或您提供的那个,则隐式生成一个。
这些时间有多快,例如:与拨打
相比memcpy
?
取决于班级及其成员。分析应该给你一个更清晰的图像
但是,应避免使用memcpy
复制类实例。
编译器如何实现这一目标?
他们为该结构执行 shallow copy 。出于所有实际目的,您可以将其视为与memcpy
相同。
答案 1 :(得分:4)
显然,如果有struct
或class
的构造函数,则调用构造函数。
如果没有构造函数,则完全取决于编译器,但很可能,对于三个整数大小的对象,它可能是三个单独的mov
指令。对于较大的结构,可以是对memcpy
的调用,也可以是与memcpy
类似的内联版本。
如果结构非常大(几兆字节),那么很可能真正的memcpy
比内联版本快,并且编译器可能没有意识到这一点并且无论如何都使用内联版本。但是我们大多数人都没有使用兆字节的大型结构,所以我不认为通常会有太多担心。如果结构大兆字节,则将结构作为参数复制到堆栈上,考虑到典型堆栈的受限大小,首先可能不是一个好主意。
答案 2 :(得分:3)
有两个令人不安的案例。
如果你的结构是 POD ,那么副本会得到优化,并且会像memcpy一样快(具有适当的优化级别)。
如果您的结构不是POD ,C ++必须为您的对象调用复制构造函数。复制构造函数可以调用其他函数,新运算符等,因此它将比memcpy慢。但是memcpy
不会正确复制结构,在非POD类型上使用memcpy
会导致未定义的行为!
请注意,例如在g++
中,对memcpy
的调用将被内联并优化。由于struct copy和memcpy调用之间的意图完全相同(从位置Y到Z复制X个字节),我认为生成的汇编代码不会有所不同。
无论如何,确定,通过分析代码的汇编来找出它。
编辑:只需阅读有关函数参数的问题的结尾。请注意,函数参数传递通常(特别是在x64中)在寄存器中完成,并且比memcpy
快得多。
我检查了汇编代码,他们做差异。确切的代码取决于您当前编译器使用的calling convention。对我来说,struct不会在寄存器中传递,而是在堆栈上传递并生成实际的副本。这三个int
在%ecx
,%edx
和%r8d
中传递。我在Windows GCC上试过这个。它似乎使用Windows x64呼叫对话。
有关如何传递参数的更多信息,请查看调用约定的规范。所有的细节和角落案例都得到了解决。例如。对于x64 GCC,请查看System V AMD64 ABI第3.2.3章参数传递。对于Visual Studio,请查看here。
答案 3 :(得分:0)