C语言中函数返回的struct赋值给栈变量时是否会发生拷贝?
问题解答
基础结论
标记here的位置大概率不会发生大结构体的全量拷贝,现在主流编译器都会做优化消除这个拷贝,具体的细节可以分两种场景说明:
未开启编译优化的场景
按照C语言的标准调用约定,对于远大于通用寄存器宽度的大体积结构体,编译器默认就会采用隐式指针传递的实现逻辑,不会真的全量拷贝返回值:
- 编译器会自动给
get_my_struct_from_file添加一个隐藏的入参,这个入参就是main函数里栈上res变量的内存地址 - 函数内部的局部变量
u的写入操作,会直接落在这个传入的地址上,等价于你手动写了void get_my_struct_from_file(const char *filename, struct my_struct *out)的写法,不需要额外拷贝 - 只有非常老旧的、不遵循现代调用约定的编译器,才会出现先在被调用函数栈上生成完整结构体,再全量拷贝到调用方变量的情况
开启编译优化的场景
只要开启了O1及以上的优化等级,现在所有主流编译器(GCC、Clang、MSVC)都会默认启用命名返回值优化(NRVO),彻底消除所有多余的拷贝操作:
- 编译器会直接将函数内部的局部变量
u和调用方的res映射到同一块内存地址 - 函数内部对
u的所有赋值操作,本质就是直接对res赋值,全程不会触发任何结构体拷贝,性能和手动传指针的写法完全一致
验证方法
你可以在编译时添加-S参数生成汇编代码自行验证:如果没有发生拷贝,汇编代码中不会出现循环复制大块内存的指令,也不会调用memcpy相关的实现逻辑。
内容的提问来源于stack exchange,提问作者Kevin Meier
相关产品推荐
相关产品推荐

