我对GCC对优化pure
函数(来自online docs)的保证感到困惑:
pure
除了返回值之外,许多函数都没有效果,它们的返回值仅取决于参数和/或全局变量。 (...)
有趣的非纯函数是具有无限循环的函数或取决于易失性内存或其他系统资源的函数,这些函数可能在两个连续调用之间发生变化(例如多线程环境中的
feof
)。
对于const
:
const
除了参数之外,许多函数不检查任何值,除了返回值之外没有任何效果。基本上,这只是比下面的纯属性稍微严格的类,因为该函数不允许读取全局内存。
请注意,具有指针参数并检查指向的数据的函数不得声明为
const
。同样,调用非const函数的函数通常不能是const。
所以,我尝试创建一个接受指针参数的函数,并尝试将其标记为pure
。但是,我尝试使用GCC在线编译此功能(我尝试了const
和pure
):
typedef struct
{
int32_t start;
int32_t end;
}
Buffer;
inline __attribute__((pure,always_inline)) int32_t getLen(Buffer * b)
{
return b->end - b->start;
}
注意到海湾合作委员会(至少我试过的几个online compiler versions):
Buffer*
参数指向全局值,const
标记为pure
,但两个案例的工作方式相同,但如果存在指针参数,则可能会忽略const
? 这是一件好事,因为全局Buffer
可能随时由不同的线程/中断更改,而本地Buffer
对于优化是完全安全的。
但是我对传递指针的言论感到困惑。是否有一个地方为接受指针参数的pure
函数明确定义了GCC的行为?
答案 0 :(得分:4)
是否存在为接受指针参数的纯函数显式定义GCC行为的地方?
行为与不带指针参数的纯函数没有什么不同;他们可以读取程序中的任何内存,但不能写入内存或执行IO。
通过将纯函数和const函数编写为内联,您已经非常困惑了。在调用站点,编译器可以使用函数体,它可以自己解决被调用函数执行的操作。 pure和const属性在函数体不可见的情况下最有用,因为它将在单独的编译单元中定义。
例如,考虑以下非纯,纯和const函数的集合:
__attribute__((__pure__)) int a();
__attribute__((__const__)) int b();
void c();
如果我们连续两次调用a
,没有操作插入,我们可以将其折叠为单个调用,因为a
只能访问全局内存才能读取它;即使另一个线程在同一时间写入全局内存,a
也无法与该线程通信,因此编译器可以假定写入发生在调用a
之前或之后:
int f() {
int i = a();
i += a();
return i; // optimized to "return a() * 2;"
}
如果我们在调用c
之间致电a
,我们必须假设调用a
可能会影响c
的返回值:
int g() {
int i = a();
c();
i += a();
return i; // no optimization possible
}
但是,如果我们调用const a
代替纯b
,我们可以将其折叠为单个调用,因为b
无法读取c
的任何内存可以写信给:
int h() {
int i = b();
c();
i += b();
return i; // optimized to "c(); return b() * 2;"
}
答案 1 :(得分:1)
“GCC提出的保证”。
没有。 pure
和const
属性是承诺 你对GCC做出的承诺。
当你做出这些承诺时,优化器可能能够建立某些变量的非别名。但即使它可以,非锯齿也可能与优化无关(因为它不够或不相关)。添加pure
和const
无关紧要。