ideone.com提供的示例:
int passByConstPointerConst(MyStruct const * const myStruct)
int passByValueConst (MyStruct const myStruct)
您是否希望编译器优化上述两个函数,以便双方都不会实际复制传递的MyStruct的内容?
我知道很多优化问题都是针对个别编译器和优化设置的,但我不能为单个编译器设计。相反,我想对是否需要传递指针以避免复制有一个普遍的期望。它似乎只是使用const
并允许编译器处理优化(在我配置之后)应该是一个更好的选择,并且会导致更易读和更少错误的代码。
对于ideone.com处的示例,编译器显然仍在将数据复制到新位置。
答案 0 :(得分:1)
在第一种情况下(将const指针传递给const)不会发生复制。
在第二种情况下,复制确实发生了,如果没有其他原因我会不期望优化,因为对象的地址被采用然后通过省略号传递给函数从编译器的角度来看,谁知道函数对该指针的作用是什么?
更一般地说,我不认为将按值调用转换为引用调用是编译器所做的事情。如果您想通过引用进行复制,请自行实施。
从理论上讲,编译器是否可以检测到它只能将函数转换为pass-by-reference?是; C标准中没有任何内容表明它不能......
你为什么担心这个?如果您担心性能,那么分析显示按值复制是您软件中的一个重要瓶颈吗?
答案 1 :(得分:1)
comp.lang.c
常见问题解答
http://c-faq.com/struct/passret.html
当通过值传递大型结构时,通常通过实际传递对象的地址而不是副本来优化。然后被调用者确定是否需要复制,或者它是否可以简单地使用原始对象。
参数上的const限定符没有区别。它不属于该类型;它完全被忽略了。也就是说,这两个函数声明是等价的:
int foo(int);
int foo(const int);
声明可以省略const,但是定义可以省略它,反之亦然。调用的优化不能取决于声明中的const
。 const
不是创建语句的对象通过值传递的语义,因此原始文件无法修改。
优化必须保留语义;它必须看起来好像是对象的副本真的通过了。
有两种方法可以判断副本未通过:一种是对明显副本的修改会影响原始副本。另一种方法是比较地址。例如:
int compare(struct foo *ptr, struct foo copy);
在compare
内,我们可以获取copy
的地址,看看它是否等于ptr
。如果即使我们已经完成了优化,那么它也会向我们展示。
答案 2 :(得分:1)
第二个声明实际上是用户直接请求接收传递结构的副本。
const
修饰符消除了对本地副本进行任何修改的可能性,但是,它并没有消除所有复制的原因。
首先,副本必须保持其地址标识,这意味着在第二个函数内&myStruct
表达式应该与任何其他MyStruct
的地址产生值不同宾语。当然,智能编译器可以检测依赖于对象的地址标识的情况。
其次,别名是另一个问题。想象一下,程序有一个全局指针MyStruct *global_struct
,在第二个函数中有人修改了*global_struct
。 *global_struct
可能与作为参数传递给函数的结构对象相同。如果没有复制,则对*global_struct
所做的修改将通过本地参数显示,这是一个灾难。在编译时要解决别名问题(通常情况下是不可能的),这就是编译器通常无法优化复制的原因。
因此,我希望任何编译器都能按要求执行复制。