为何返回C99复合字面量会生成更多汇编代码?
问题:为何复合字面量返回结构体比变量初始化返回生成更多汇编代码?
给出的两个C函数,一个通过复合字面量返回结构体,另一个先初始化变量再返回:
typedef struct { int storage[256]; } data_t; data_t data_init_compound_literal() { return (data_t){ .storage = {1} }; } data_t data_init_var() { data_t self; self.storage[0] = 1; return self; } int main(void) { data_t em = data_init_compound_literal(); return em.storage[0]; }
使用-O2优化选项生成汇编后,复合字面量方式的函数生成的代码行数明显更多:
data_init_compound_literal: movq $0, (%rdi) movq %rdi, %rdx leaq 8(%rdi), %rdi xorl %eax, %eax movq $0, 1008(%rdi) movq %rdx, %rcx andq $-8, %rdi subq %rdi, %rcx addl $1024, %ecx shrl $3, %ecx rep stosq movl $1, (%rdx) movq %rdx, %rax ret data_init_var: movl $1, (%rdi) movq %rdi, %rax ret main: movl $1, %eax ret
原因解析
两者的核心差异源于C语言标准对初始化行为的不同要求:
- 复合字面量的
(data_t){.storage = {1}}属于聚合初始化,根据C标准,聚合类型中未显式指定的元素必须被初始化为对应类型的零值(这里就是int的0)。因此编译器必须生成代码,将整个storage数组的256个元素全部清0,再把第一个元素设为1。 - 而
data_init_var函数中,局部结构体变量self默认是未初始化状态(栈上的原始垃圾值),标准没有要求未赋值的元素必须为0,编译器只需要保证storage[0]被设为1即可,其他元素无需处理。
在-O2优化下,编译器严格遵循标准规则:
- 复合字面量版本需要完成全数组的清0操作,汇编中出现的
rep stosq就是批量写0的高效指令,用来初始化整个数组,这也是代码行数更多的原因。 - 变量初始化版本仅需设置第一个元素的值,因此汇编代码极为简洁。
注:main函数的汇编被优化为直接返回1,是因为编译器能直接推导函数调用的最终结果,属于独立的优化,和两个初始化函数的差异无关。
内容的提问来源于stack exchange,提问作者edugomez102
相关产品推荐
相关产品推荐

