这些属性允许编译器知道在不知道它是如何实现的情况下省略对函数的调用是否安全。
纯属性基本上是说函数结果只取决于函数参数和全局状态;此外,函数本身不会改变全局状态。
如果你两次调用一个纯函数,保证返回相同的结果;但是,如果您在调用之间改变全局可见状态,则保证不再成立。
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 次调用未知;test4() 调用 bar(),然后调用 unknown(),并返回 bar() 的结果乘以 2。
这种行为符合上面的解释——unknown() 可以改变全局状态,所以编译器不能省略对 foo() 的额外调用,但可以省略对 bar() 的额外调用。