在 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) 之间有什么区别,或者生成的汇编代码是否相同(考虑到参数的传递)?
编译器如何实现这一点?
他们调用该类/结构的复制构造函数。如果您不提供一个或您提供的一个,则隐式生成一个。
例如,与调用相比,这些速度有多快
memcpy
?
取决于类及其成员。剖析应该给你一个更清晰的画面。
但是,memcpy
应避免使用复制类实例。
编译器如何实现这一点?
他们为该结构执行浅拷贝。出于所有实际目的,您可以将其视为与memcpy
.
显然,如果struct
or有构造class
函数,则调用构造函数。
如果没有构造函数,则完全取决于编译器,但最有可能的是,对于三个整数大小的对象,它可能是三个单独的mov
指令。对于较大的结构,它可以是对 . 的调用memcpy
或类似的内联版本memcpy
。
如果结构非常大(几兆字节),也很有可能memcpy
比内联版本更快,编译器可能没有意识到这一点并使用内联版本。但是我们大多数人不使用兆字节的大型结构,所以我认为一般来说这不是太担心的事情。考虑到典型堆栈的大小有限,如果结构是兆字节大,则将结构作为参数复制到堆栈上可能不是一个好主意。
有两种不同的情况。
如果您的 struct 是POD,则副本将被优化并且将与 memcpy 一样快(具有适当的优化级别)。
如果您的 struct不是 POD,则 C++ 必须为您的对象调用复制构造函数。复制构造函数可能会调用其他函数、new 运算符等,因此它会比 memcpy 慢。但memcpy
不会正确复制结构,memcpy
在非 POD 类型上使用会导致未定义的行为!
请注意,例如在g++
调用memcpy
中将被内联和优化。由于结构复制和 memcpy 调用之间的意图完全相同(将 X 字节从位置 Y 复制到 Z),我认为生成的汇编代码不会有所不同。
无论如何,可以肯定的是,通过分析代码的汇编来找出它。
编辑:只需阅读有关函数参数的问题的结尾即可。请注意,函数参数传递通常(尤其是在 x64 中)在寄存器中完成,它比memcpy
.
我检查了汇编代码,它们确实不同。确切的代码将取决于您当前编译器使用的调用约定。对我来说,结构没有在寄存器中传递,而是在堆栈上传递并制作了实际的副本。三个int
s 传入%ecx
,%edx
和%r8d
。我在 Windows GCC 上试过这个。它似乎使用 Windows x64 调用对流。
有关如何传递参数的更多信息,请查看调用约定的规范。所有细节和极端案例都已制定。例如,对于 x64 GCC,请查看 System V AMD64 ABI 第 3.2.3 章参数传递。对于 Visual Studio 看这里。
请参阅Alok Save for c++的另一个答案。在c中,它可以是(或等效的)或它的内联版本(对于具有良好大小的结构memcpy
最多一个指令)。mov