我最近写了很多程序来struct
绕过函数,以避免全局变量.但是,我想知道传递struct
自身或其指针是否更有效.它听起来应该是这样,因为指针(在我的64位GNU/Linux系统上)是8个字节,而struct
充满指针显然远不止于此.
但是,如果我有这个struct
:
struct Point { int x; int y; }
这是8个字节,与指针大小相同,是将整个struct
传递给函数还是传递指针更好?我非常精通C内存分配,因此malloc
在初始化指针时使用和朋友不是问题.
另一个想法是,如果它们很大,直接传递结构会占用大量的堆栈空间.然而,简单地使用指针会耗尽内存,这free
很容易编辑.
[ 这个问题和它的答案对传递结构与结构指针的优点和缺点进行了相当彻底的一般处理.这个答案打算处理这个问题中提到的特定情况,即8字节结构与8字节指针以及在寄存器中传递参数的ABI.
在运行Linux的64位Intel CPU上,ABI 要求通过寄存器传递8个字节的参数,直到不再剩下.例如,第一个通过%rdi
寄存器传递.这与优化无关.这是ABI的要求.
在这种特殊情况下(8字节结构与8字节指针),指针和结构都将通过一个寄存器传递.即两种情况都不使用堆栈.事实上,如果你有一个简单的功能,如:
int add (struct Point p) { return p.x + p.y; }
..并且编译时gcc -O1
,该函数甚至没有堆栈帧.
您可以在生成的代码中看到这一点(x86_64 Linux gcc
5.1,with -O1
):
# Passing the struct: movq %rdi, %rax sarq $32, %rax addl %edi, %eax ret # Passing a pointer to the struct: # [each (%rdi) is a memory access] movl 4(%rdi), %eax addl (%rdi), %eax ret
但正如您所看到的,指针版本访问内存两次.因此,传递值更快.传递指针将生成内存访问,以获取结构的成员.然后还有一个额外的风险,即结构可能位于未被CPU缓存缓存的内存块上,并且访问将导致缓存未命中.这不应该发生,因为通常,调用者只是访问了相同的结构,因此它在缓存上.
在32位Linux上,int
s继续为4个字节,但指针变小(8到4).并且由于参数在堆栈上传递,这意味着传递指针会在堆栈上保存4个字节(8字节结构,而不是4字节指针).但我仍然喜欢通过改变空间局部性来传递价值.