c - 传递结构指针与传递结构

标签 c linux pointers struct

我最近编写了很多程序,这些程序在函数周围传递 struct,以避免全局变量。但是,我想知道传递 struct 本身或其指针是否更有效。听起来应该是这样,因为指针(在我的 64 位 GNU/Linux 系统上)是 8 个字节,而充满指针的 struct 显然比这多得多。

但是,如果我有这个 struct:

struct Point {
    int x;
    int y;
}

也就是8个字节,和指针大小一样,是把整个struct传给一个函数好,还是传一个指针好?我相当精通 C 内存分配,因此在初始化指针时使用 malloc 和 friend 不是问题。

我的另一个想法是,如果结构很大,直接传递结构可能会占用大量堆栈空间。然而,简单地使用指针会耗尽内存,这可以很容易地释放

最佳答案

[ 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 字节指针)。 但我仍然喜欢按值(value)传递,因为它改善了空间局部性。

关于c - 传递结构指针与传递结构,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34223458/

相关文章:

linux - 为什么 "df"和 "du"在 LVM 卷上显示不同的已用空间值?

c - 写入EEPROM的算法?

c - while 循环出现两次

c - 如何将这段代码转换为递归函数?基本案例分析

linux - 如何将cacaview的结果输出到文件中?

linux - 解压文件而不使用第一个目录

c 指向结构的自由指针

c++ - 在 "for"循环中初始化两个指向相同值的指针

C 链表指针问题(无限循环)

c - 在二叉树中使用指针