Warning: file_get_contents(/data/phpspider/zhask/data//catemap/7/sqlite/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ C/C++;复制结构?_C++_C_Struct_Copy - Fatal编程技术网

C++ C/C++;复制结构?

C++ C/C++;复制结构?,c++,c,struct,copy,C++,C,Struct,Copy,在C/C++中按值传递结构时,必须复制结构内容。编译器是如何实现的?即,此副本通常发出哪些装配说明 这些速度有多快,例如,与呼叫memcpy相比 现在考虑这个代码: struct X { int i, j, k; }; void foo(X x); void foo( int i, int j, int k); < P>在调用FoO(x)和FoO(int,int,int)之间是否有区别,或者在C++中,生成的汇编代码是否相同(考虑参数的传递)? 编译器是如何做到这一点的? 他们为该类/结构

在C/C++中按值传递结构时,必须复制结构内容。编译器是如何实现的?即,此副本通常发出哪些装配说明

这些速度有多快,例如,与呼叫memcpy相比

现在考虑这个代码:

struct X { int i, j, k; };

void foo(X x);

void foo( int i, int j, int k);
< P>在调用FoO(x)和FoO(int,int,int)之间是否有区别,或者在C++中,生成的汇编代码是否相同(考虑参数的传递)? 编译器是如何做到这一点的?

他们为该类/结构调用复制构造函数。如果您未提供或您提供的,则隐式生成一个

当(例如)与调用
memcpy
相比时,它们的速度有多快?

取决于类及其成员。分析应该能让您更清楚地了解情况。
但是,应该避免使用
memcpy
复制类实例

在C中 编译器是如何做到这一点的?


它们对该结构执行。对于所有的实际用途,您可以考虑与<代码> MycPy相同。在中,它可以是
memcpy
(或等效)或它的内联版本(对于大小合适的结构,最多可以是一个
mov
指令)。

显然,如果
结构
有一个构造函数,则调用该构造函数

如果没有构造函数,则完全由编译器决定,但对于三个整数大小的对象,很可能是三条独立的
mov
指令。对于较大的结构,它要么调用
memcpy
,要么调用类似于
memcpy
的内联版本


如果结构非常大(数兆字节),那么true
memcpy
也很可能比内联版本快,并且编译器可能没有意识到这一点,并且仍然使用内联版本。但是我们大多数人都不使用兆字节的大型结构,所以我不认为这是一个需要太多担心的问题。如果结构是兆字节大的,那么将结构作为参数复制到堆栈上可能不是一个好主意,因为典型堆栈的大小有限

有两种不同的情况

  • 如果您的结构是POD,则副本将进行优化,速度将与memcpy一样快(具有适当的优化级别)

  • > P>如果你的结构是<强>不是POD< /St>,C++必须调用对象的复制构造函数。复制构造函数可能会调用其他函数、新运算符等,因此它将比memcpy慢。但是
    memcpy
    不会正确复制结构,在非POD类型上使用
    memcpy
    会导致未定义的行为

请注意,例如在
g++
中,对
memcpy
的调用将被内联并优化。由于struct copy和memcpy调用的意图完全相同(将X字节从位置Y复制到Z),因此我认为生成的汇编代码不会有所不同

无论如何,可以肯定的是,通过分析代码的汇编找到它


编辑:只需阅读有关函数参数的问题的结尾。请注意,函数参数传递通常(特别是在x64中)在寄存器中完成,并且比
memcpy
快得多

我已经检查了汇编代码,它们确实不同。确切的代码将取决于当前编译器使用的代码。对我来说,结构不是在寄存器中传递的,而是在堆栈中传递的,并生成一个实际的副本。三个
int
s被传入
%ecx
%edx
%r8d
。我已经在Windows GCC上试过了。它似乎使用Windows x64调用Convertion


有关如何传递参数的更多信息,请参阅调用约定的规范。所有细节和角落案例都已解决。例如,对于x64 GCC,查看系统V AMD64 ABI第3.2.3章参数传递。对于Visual Studio外观。

为什么不分析它并找出答案?所有编译器都支持生成程序集文件而不是对象文件的选项。使用该工具,并亲自查看组件。此外,编译器是否真的进行了复制也取决于优化。@Luchian Grigore:因为我的评测结果可能只适用于我的机器或编译器。我想有人有更深的知识比我的评测更好。@Joachim Pileborg:再说一次,这只适用于我的编译器和代码。有可能使用另一个编译器生成完全不同的代码。因此,我想从了解这个过程背后细节的人那里知道这一点,而不是从一个不知道为什么会生成这些指令的测试中知道。如果你想要一个对所有平台和所有编译器都有效的通用答案,你将得不到任何答案。你能做的唯一一件事就是用你的编译器在你的平台上检查它是如何为你、为你的程序工作的?在C++中自动生成的复制构造函数中,我知道它们执行浅拷贝。但是,这是如何实现的。@gexicide然而,编译器认为在特定情况下是合适的。但是,对于一堆
int
s来说,使用通用
memcpy
是非常愚蠢的,而且你可以(通常)假设你的编译器没有那么愚蠢。非常有趣。这意味着,在函数参数的情况下,结构版本应该更慢。为什么编译器会错过这个简单的优化机会?编译器无法在这里进行真正的优化。如何调用函数是一成不变的(在调用约定规范中),因此编译器只需遵守规范。这允许将不同翻译单元中的两个功能链接在一起。(我说的当然是非内联函数)是吗