C语言是否允许NRVO形式复制消除?下述程序退出值是否有明确保证?
关于C语言NRVO复制消除及程序退出值的问题
问题内容
- C语言是否允许以**named return value optimization(NRVO,具名返回值优化)**形式进行复制消除?
- 下述C程序是否保证以0退出?还是编译器可以像C++中允许的那样,将对象
s和t视为同一对象?
给出的代码如下:
typedef struct { int i, j; double a, b; } S; int result; S test(S *q) { S s = {0, 0, 0, 0}; result = &s == q; return s; } int main(void) { S t = test(&t); return result; }
注:Clang运行该程序退出值为1;在C++中因明确允许NRVO,0和1均为合法输出结果。
解答
1. C语言对NRVO形式复制消除的规定
C标准并未像C那样明确允许NRVO。不过C标准允许编译器进行**复制消除(copy elision)**优化,但适用场景与C存在差异:
- C标准中的复制消除主要针对返回未命名临时对象的情况(类似C++的RVO),对于具名局部变量(如代码中的
s)的返回优化,标准没有明确授权编译器将其与调用端对象(如t)合并。 - 编译器可在不改变程序可观测行为的前提下优化,但C标准对变量的生存期和身份有严格要求:局部变量
s是test函数内的独立对象,其地址必须与调用端的t不同,除非标准明确允许合并。
2. 程序的退出值分析
根据C标准规定,该程序必须保证以0退出:
test函数中的局部变量s是独立的自动存储期对象,它的地址&s和传入的&t(main中t的地址)是两个不同指针,因此&s == q的结果必为假,result会被赋值为0,程序最终返回0。- Clang返回1的行为违反了C标准,它错误套用了类似C++的NRVO优化,将
s和t的存储合并,但C语言不允许编译器通过优化抹除两个不同对象的身份差异,指针比较结果必须符合对象实际存储位置。
内容的提问来源于stack exchange,提问作者user17732522
相关产品推荐
相关产品推荐

