提问人:Zaratruta 提问时间:8/26/2022 更新时间:8/26/2022 访问量:435
将结构作为参数按值传递给函数是否有效?
Is it efficient passing structs as parameters by value to a function?
问:
据我所知,结构可以作为参数按值传递,或者我们也可以使用指针通过引用传递它。
按值传递结构是否有效?如果我们有很多字段的大结构体,这似乎效率不高,因为结构体数据被复制到函数的形式参数中,这涉及计算成本。
在这些情况下,通过引用传递结构似乎是更好的选择。这有意义吗?
另一个相关的问题是,编译器是否在这个意义上进行优化,将传递值的参数转换为引用。
答:
它肯定不会有效率,但有时我们想处理局部自动变量。当您更改自动变量时,当函数返回时,它将停止存在,并且所有更改将仅对此局部变量进行。如果它是由指针传递的,则函数将修改原始对象,而不是本地对象。因此,编译器不会对其进行优化。
typedef struct
{
double x[10000];
}big_struct;
void __attribute__((noinline)) foo(big_struct bs)
{
for(size_t i =0; i < sizeof(bs.x) / sizeof(bs.x[0]); i++) printf("%f\n", bs.x[i]);
}
void bar(void)
{
big_struct x;
/* some code */
foo(x);
}
.LC0:
.string "%f\n"
foo:
push rbp
push rbx
sub rsp, 8
lea rbx, [rsp+32]
lea rbp, [rsp+80032]
.L2:
movsd xmm0, QWORD PTR [rbx]
mov edi, OFFSET FLAT:.LC0
mov eax, 1
add rbx, 8
call printf
cmp rbx, rbp
jne .L2
add rsp, 8
pop rbx
pop rbp
ret
bar:
sub rsp, 160008
mov edx, 80000
lea rsi, [rsp+80000]
mov rdi, rsp
call memcpy
call foo
add rsp, 160008
ret
评论
如果结构很小,则按值传递它。现代调用约定允许在合适的平台上传递寄存器中的小结构。
如果结构很大,则可以定义例程以通过引用(使用指向限定类型的指针)接收结构。const
还应该使用 声明指针,如 中所示。否则,通过引用传递结构可能会影响优化。请考虑传递给同样具有参数 或 的例程。在例程中,如果代码更改了指向或指向的结构,则编译器通常无法知道哪个没有指向与结构指向相同的结构,或者哪个没有指向作为结构成员指向的 a。这可能会导致编译器多次重新加载数据,而实际上没有发生任何更改。using 告诉编译器调用方不会传递 a,因此使用 via 的数据也不会通过其他点在例程中使用。restrict
const struct foo * restrict p
const struct foo *p
struct foo *q
float *f
q
float
f
q
p
f
float
p
p
p
restrict
p
p
另一个相关的问题是,编译器是否在这个意义上进行优化,将传递值的参数转换为引用。
这并不常见。但是,通过引用返回结构是很常见的。调用约定通常是调用方为返回的结构提供要写入的位置,并传递指向该位置的指针,不可见地指向源代码。
评论
void x(foo) {}