我发现复合文字是将初始化的数组和 struct 发送到函数而无需编写过多冗长代码的一种非常有用和优雅的方法,但我想了解以这种方式编写代码的成本,例如下面这个简单的胡说八道的程序:
#include <stdio.h>
struct st{
int a;
int b;
};
int foo(struct st bar){
return bar.a * bar.b;
}
int main(void){
printf("%d %d\n", foo((struct st){.a=4, .b=6}), foo((struct st){.a=7, .b=19}));
}
毫无怨言地编译,并按预期输出24 133
个.
我可以修改伪代码,使函数接受指向struct st
的指针,而不是值:
#include <stdio.h>
struct st{
int a;
int b;
};
int foo(struct st *bar){
return bar->a * bar->b;
}
int main(void){
printf("%d %d\n", foo(&(struct st){.a=4, .b=6}), foo(&(struct st){.a=7, .b=19}));
}
编译器不会介意,输出也不会改变.显然,我要求编译器做的事情在这些情况下是不同的.在第一个示例中,编译器可以注意到复合文字是通过值发送给函数的,因此在调用foo()
之后,main()
中的任何future 代码都完全无法到达通过值发送的复合文字.在我看来,从理论上讲,编译器可以注意到这一点,并占用相同的内存空间来满足对两个文字的请求,可能会像这样重新分析Main函数:
int main(void){
struct st a = {4,6};
int ret1 = foo(a);
a.a = 7;
a.b = 19;
int ret2 = foo(a);
printf("%d %d\n",ret1, ret2);
}
但在代码的第二个版本中,文字是通过引用发送的,因此编译器可能无法轻松推断他们的内存是可删除的,可能会这样解释代码:
int main(void){
struct st a = {4,6};
struct st b = {7,19};
int ret1 = foo(&a);
int ret2 = foo(&b);
printf("%d %d\n",ret1, ret2);
}
在我的理解中,这迫使编译器分配更多的堆栈内存来完成相同的任务.
这是对正在发生的事情的准确判断吗?C标准是否允许编译器重用技术上仍在作用域内的内存?
如果不是,这是否意味着代码如下:
for(int c = 0; c < SOME_RUNTIME_VALUE; ++c)
printf("%d\n", foo((struct st){.a = c/4, .b = c%4}));
强制编译器将未知数量的内存分配到堆栈上?如果它们是按值发送还是按引用发送,与堆栈内存方面有区别吗?