我最近写了很多程序,它们围绕函数传递struct
,以避免全局变量。但是,我想知道传递struct
本身或其指针是否更有效。它听起来应该是这样,因为指针(在我的64位GNU / Linux系统上)是8个字节,而一个struct
充满指针显然远不止这些。
但是,如果我有struct
:
struct Point {
int x;
int y;
}
这是8个字节,与指针大小相同,是将整个struct
传递给函数还是传递指针更好?我非常精通C内存分配,因此在初始化指针时使用malloc
和朋友不是问题。
我的另一个想法是,如果它们很大,直接传递结构会占用大量的堆栈空间。但是,只需使用指针就会耗尽内存,可以轻松free
。
答案 0 :(得分:8)
[This question并且它的答案对传递结构与结构指针的优点和缺点进行了相当彻底的一般处理。这个答案打算处理这个问题中提到的具体情况,即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,-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
继续为4个字节,但指针变小(8
到4)。并且由于参数在堆栈上传递,这意味着传递
指针在堆栈上保存4个字节(8字节结构,4字节指针)。
但我仍然喜欢通过改进的空间位置来传递价值。