考虑这段代码:
typedef struct my_struct { int a; int b; int c; } my_struct;
void some_function(my_struct *value)
{
// do something
}
int main(void)
{
for (;;) {
some_function(&(my_struct){1, 2, 3});
}
return 0;
}
我计划始终将
a
、b
和 c
设置为 1
、2
和 3
。因此,传递给 some_function
的对象将始终是相同的。在这种情况下,编译器是否在每次迭代时重新创建并重新销毁对象?或者它是否将其转换为类似的东西:
typedef struct my_struct { int a; int b; int c; } my_struct;
void some_function(my_struct *value)
{
// do something
}
int main(void)
{
my_struct once_and_for_all = {1, 2, 3};
for (;;) {
some_function(&once_and_for_all);
}
return 0;
}
它不会在循环中进行任何内存分配/释放,并以最佳速度运行。
我更喜欢第一种语法,因为它不太冗长,但我也担心性能。
我使用海湾合作委员会。
拆开看看。只需首先声明具有外部链接的函数,然后将函数定义保留在代码之外,这样编译器就无法对其进行任何假设:
void some_function (my_struct *value);
然后 gcc -O3 for x86 给出:
main:
push rbp
push rbx
sub rsp, 24
mov rbp, QWORD PTR .LC0[rip]
mov rbx, rsp
.L2:
mov rdi, rbx
mov QWORD PTR [rsp], rbp
mov DWORD PTR [rsp+8], 3
call some_function
jmp .L2
.LC0:
.long 1
.long 2
也就是说:堆栈空间被保留一次,但在循环的每一圈,值都会被复制到该空间中。由于该函数没有
const
限定参数,因此编译器无法假设该函数未修改这些值。
但是,将参数更改为
const my_struct *value
并没有改进代码。这似乎是一个错过的优化,因为我想不出 C 标准中的任何内容会迫使编译器在函数参数为 const
时一遍又一遍地更新文字。 clang 的行为是一样的。
手动优化代码修复了问题:
const my_struct* ptr = &(const my_struct){1, 2, 3};
for (;;) {
some_function(ptr);
}
然后我们得到:
.L2:
mov rdi, rbx
call some_function
jmp .L2