2012-01-31 60 views
15

我有一个指针int* p,并在循环中做一些操作。我不修改内存,只是阅读。如果我将const添加到指针(这两种情况下,const int* pint* const p),它可以帮助编译器优化代码吗?可以给指针添加'const'来帮助优化吗?

我知道const的其他优点,比如安全性或自我记录,我问这个特殊情况。改写这个问题:const可以给编译器提供任何有用的信息吗?

+3

你真的是指'int const * p'吗?或者'int * const p'?什么循环?你在迭代什么? – 2012-01-31 10:46:18

+1

你可以做到这一点,并比较生成的代码: - ? – cnicutar 2012-01-31 10:47:05

+1

确定给定的CPU,编译器,操作系统等的唯一方法是对其进行基准测试,结果将仅适用于该特定配置。这听起来像是对我来说过早的优化。 – 2012-01-31 10:49:41

回答

6

虽然这很明显是特定于实现,但很难看出如何将指针从int*更改为int const*可以提供编译器本来不知道的任何其他信息。

在这两种情况下,在执行循环期间,指向的值都可能会发生变化。

因此,它可能不会帮助编译器优化代码。

+0

这简直是错的; 'int const *'等同于'const int *',它不会指向可写内存。 (你的意思可能是'int * const') – 2013-12-15 02:37:56

+1

@JoSo:不,这是正确的。所有'int const *'指出的是'int'不能通过特定的指针修改。如果'int'最初是非const的,那么它可以被代码的另一部分修改,或者可以在转换后由代码的相同部分修改。 – Mankarse 2013-12-15 22:37:08

+0

我的回答错误了,无法回顾这是怎么回事。对不起。更糟糕的是,除非答案被编辑,否则显然不允许删除(向下)投票...... :( – 2013-12-16 00:02:57

2

它可以帮助或它可以没有区别或它可以使情况变得更糟。要知道的唯一方法是尝试并检查发出的机器代码。

现代编译器非常聪明,所以他们经常可以推断出没有任何限定符的内存没有改变(如果没有代码编写方式更容易分析,他们可以推断出许多其他优化是可能的),但它们相当复杂,所以有一个很多缺陷,并且往往无法在每一个机会上优化每一件可能的事情。

+0

你有什么可以让它变得更糟的例子吗? – 2012-01-31 11:00:18

+0

@Jakub M .:不是针对这个特定的情况,但是当编译器无法发出最优代码时,我已经看到了几十个案例。 – sharptooth 2012-01-31 11:28:21

+2

*它可以使情况变得更糟*除非有一个例子证明,'const'可以没有区别或*有一些*区别,它们之间的差异可以忽略不计,因此不会将其用作优化标准,它只能用于编写更正确的可维护代码。 – 2012-01-31 11:38:51

3

不可以。使用const就不会为编译器提供任何可用于优化的信息。

理论上,对于编译器来说,优化器必须能够证明没有人会在你的const指针上使用const_cast,但无法证明变量永远不会被写入。这种情况极不可能。

香草萨特涵盖这是更深入他的Guru of the Week列之一。

+0

)如果编译器*能够证明所有附加信息,那么它不再需要'const'限定。即使那样'const'也不会帮助优化。 – Mankarse 2012-01-31 11:21:55

+0

@Mankarse:除非出于一些愚蠢的特定于实现的原因,例如除非指针是const限定的,否则一个特定的优化器不会干扰分析。但是你说的话仍然正确,因为根据我的论点*任何*都会影响优化 - 变量名称中的元音数量,或者是否缩进制表符和空格。唯一的问题是,优化程序在某些情况下忽略某些潜在有用的信息而非其他情况的可能性有多大。 – 2012-01-31 12:32:45

1

我认为编译器不能在你的场景中做很多事情。您的指针声明为const int * const p并不能保证内存无法在外部进行更改(例如,由另一个线程。因此,编译器必须生成读取循环的每次迭代中的内存值的代码。

但如果不会写入到内存的位置和知道,没有其他的代码会,那么你可以创建一个局部变量,并用它与此类似:

const int * p = ... 
... 
int val = *p; 
/* use the value in a loop */ 
for (i = 0; i < BAZILLION; i++) 
{ 
    use_value(val); 
} 

不仅可以帮助潜在的代码读者看到val在循环中未发生更改,而且还使编译器有可能进行优化(例如,在寄存器中加载val)。

+2

编译器通常不会考虑其他线程,除非您专门添加volatile。任何函数调用都会阻碍。 – 2012-01-31 14:01:40

+0

@PerJohansson:你可能是对的。无论如何,另一个线程只是一个例子。任何函数调用的副作用也是一个很好的例子。我只想指出,编译器执行的任何优化必须(并且确实!)保留了代码的原始语义,而优化循环内部的内存读取当然不会,因此也不会执行。但是由于没有合法的方法可以在外部(函数体外部)更改'val',因此编译器可以自由优化。 – 2012-01-31 14:16:00

1

正如其他人所说的,使用const不太可能帮助编译器优化您的循环。

但是,它可能会帮助优化代码以外的循环,或者在调用const限定方法的位置或者接受const参数的函数。

这很可能取决于编译器是否可以证明它允许消除冗余负载,移动它们或缓存计算值而不是重新计算它们。

证明这一点的唯一方法仍然是对配置文件进行配置和/或检查,但这正是您应该查找的位置。

1

你不说你正在使用哪种编译器。但是,如果你正在阅读和写作内存,你可以从使用“限制”或类似的东西中受益。编译器不知道你的指针是否是别名相同的内存,所以任何商店经常强制再次加载其他值。 “restrict”告诉编译器指针不会发生混叠,并且可以继续使用在后续写入之前加载的值。避免别名问题的另一种方法是将您的值加载到局部变量中,然后在编写之后编译器不会被强制重新加载。