来自GCC文档:
许多函数除了参数外不检查任何值,并且除了返回值之外没有任何效果。基本上这只是类比上面的纯属性稍微严格一些,因为函数不允许读取全局内存。
我的问题是全局const
值是否算作全局内存。我认为是这样,但我明确标记为不变的值可能会否定这里可能的优化,这似乎很奇怪。
例如:
int const ConstantModulusValue = 3;
int foo(int value) {
return foo % ConstantModulusValue;
}
根据我的理解,使用ConstantModulusValue
意味着这个函数不应该标记为const
,这对我来说又很奇怪。标记这个const
有什么危险吗。?
这些属性允许编译器知道在不知道函数是如何实现的情况下省略对函数的调用是否安全。
纯属性基本上说函数结果只取决于函数参数和全局状态;此外,函数本身不会改变全局状态。
如果你两次调用纯函数,它肯定会返回相同的结果;但是,如果在调用之间更改全局可见状态,则保证不再有效。
const属性更强,因为即使全局状态发生了变化,函数仍然应该返回相同的结果;因此,在更多情况下优化对const函数的冗余调用是安全的。
如果可以保证全局状态不变,那么读取全局状态应该不会成为问题(请注意,将全局标记为const并不总是保证这一点)。
举个例子,考虑一下这个程序:
int foo(int) __attribute__((pure));
int bar(int) __attribute__((const));
void unknown();
int test1(int a)
{
int x = foo(a);
int y = foo(a);
return x + y;
}
int test2(int a)
{
int x = bar(a);
int y = bar(a);
return x + y;
}
int test3(int a)
{
int x = foo(a);
unknown();
int y = foo(a);
return x + y;
}
int test4(int a)
{
int x = bar(a);
unknown();
int y = bar(a);
return x + y;
}
用gcc 4.8.1编译并分析程序集表明,test1()和test2()都只调用各自的函数一次,然后将结果乘以2;test3()执行3次调用-2次调用foo,1次调用unknown;test4()先调用bar(),然后调用unknown(),并返回bar()的结果,再乘以2。
这种行为与上面的解释相匹配-unknown()可以改变全局状态,所以编译器不能消除对foo()的额外调用,但可以消除对bar()的多余调用。