C语言循环中传递常量结构体:两种实现的性能孰优?
循环中传递常量结构体:复合字面量 vs 提前定义常量变量的性能对比
我有一段循环调用函数的C语言代码,函数参数是编译时常量结构体。我知道可以用复合字面量(compound literal)创建匿名结构体字面量,但因为复合字面量的生命周期仅限于创建它的作用域,担心循环里用会反复创建销毁结构体,所以把结构体定义成了循环外的常量变量。相关代码如下:
struct Struct { int x, y, z; }; extern void func(struct Struct); void test1(void) { for (int i = 1000000; i--;) func((struct Struct){1, 2, 3}); } void test0(void) { const struct Struct s = {1, 2, 3}; for (int i = 1000000; i--;) func(s); }
我通过测试发现,test1似乎在循环内构造数据;即使添加-Os优化选项,两个函数的汇编代码仍有差异。有人称优化编译器应为行为一致的结构生成最优且相同的代码,请问哪种写法实际性能更优?
性能分析
- test0写法(提前定义常量):结构体
s在函数初始化阶段就会被分配到只读数据段(因为加了const),循环里每次调用func时直接传递这个已存在的结构体的副本(或根据调用约定直接把常量值加载到寄存器/栈上),不会有重复构造的开销。 - test1写法(循环内复合字面量):如果编译器优化不到位,确实会在每次循环里重新构造结构体——也就是把1、2、3这三个常量值重新写入栈上的临时结构体,再传递给
func。即使开了-Os,部分编译器可能因为复合字面量的作用域规则,没有完全把它提升到循环外,导致额外的内存写入操作。
为什么优化后的汇编仍有差异?
虽然理论上两种写法的行为完全一致,但编译器的优化逻辑是分阶段的:复合字面量属于表达式级别的构造,编译器需要先确认它没有被修改、没有依赖循环内的变量,才会把它提升到循环外。部分编译器的优化器对复合字面量的处理优先级低于提前定义的常量变量,所以会生成不同的汇编。
结论
实际场景下test0的性能更稳定更优:
- 提前定义的
const结构体明确告诉编译器这是一个只读常量,编译器可以直接把它放到只读数据区,循环里直接复用,不会有额外的构造开销。 - 复合字面量虽然在理想情况下能被优化成和test0一样,但依赖编译器的优化力度,不同编译器、不同优化选项下可能出现不一致的结果。
内容的提问来源于stack exchange,提问作者CPlus
相关产品推荐
相关产品推荐

