0

ideone.com上提供的示例:

int passByConstPointerConst(MyStruct const * const myStruct)
int passByValueConst       (MyStruct const         myStruct)

您是否希望编译器优化上面的两个函数,使得它们都不会真正复制传递的 MyStruct 的内容?

我确实了解许多优化问题特定于单个编译器和优化设置,但我不能为单个编译器进行设计。相反,我想对是否需要传递指针以避免复制有一个普遍的期望。似乎使用const并允许编译器处理优化(在我配置它之后)应该是一个更好的选择,并且会产生更清晰和更不容易出错的代码。

ideone.com的示例中,编译器显然仍在将数据复制到新位置。

4

3 回答 3

1

在第一种情况下(将 const 指针传递给 const)不会发生复制。

在第二种情况下,复制确实发生了,如果没有其他原因,我希望它被优化,因为对象的地址被获取,然后通过省略号传递到函数中,从编译器的角度来看,谁知道该函数对该指针的作用?

更一般地说,我不认为将按值调用更改为按引用调用是编译器所做的事情。如果您想通过引用进行复制,请自行实现。

从理论上讲,编译器是否有可能检测到它可以将函数转换为按引用传递?是的; C标准中没有任何内容说它不能..

你为什么担心这个?如果您关心性能,那么按值进行的分析是否显示为您软件的一个重要瓶颈?

于 2012-11-16T17:30:30.160 回答
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。如果即使我们已经这样做了优化仍然发生,那么它就会向我们展示自己。

于 2012-11-16T17:46:53.253 回答
1

第二个声明实际上是用户直接请求接收传递的结构的副本

const修饰符消除了对本地副本进行任何修改的可能性,但是,它并不能消除复制的所有原因。

首先,副本必须保持其地址标识,这意味着在第二个函数内部,&myStruct表达式应该产生一个与任何其他对象的地址不同的值。MyStruct当然,智能编译器可以检测依赖于对象地址标识的情况。

其次,混叠带来了另一个问题。想象一下,程序有一个全局指针MyStruct *global_struct,并且在第二个函数中有人修改了*global_struct. 有可能*global_struct是作为参数传递给函数的相同结构对象。如果没有复制,对 的修改*global_struct将通过本地参数可见,这是一场灾难。在编译时解决别名问题要困难得多(通常情况下不可能),这就是编译器通常无法优化复制的原因。

所以,我希望任何编译器都能按要求执行复制。

于 2012-11-16T18:03:37.023 回答