C语言 为什么没有对GCC中错误使用__attribute__((pure))给出警告?



我试图理解纯函数,并且一直在阅读有关该主题的维基百科文章。我编写了最小的示例程序,如下所示:

#include <stdio.h>
static int a = 1;
static __attribute__((pure)) int pure_function(int x, int y)
{
return x + y;
}
static __attribute__((pure)) int impure_function(int x, int y)
{
a++;
return x + y;
}
int main(void)
{
printf("pure_function(0, 0) = %dn", pure_function(0, 0));
printf("impure_function(0, 0) = %dn", impure_function(0, 0));
return 0;
}

我用gcc -O2 -Wall -Wextra编译了这个程序,期望应该发出错误,或者至少是一个警告,用于用__attribute__((pure))装饰impure_function()。但是,我没有收到任何警告或错误,并且该程序也运行没有问题。

__attribute__((pure))标记impure_function()不是不正确吗?如果是这样,为什么即使使用-Wextra-Wall标志,它也能编译时没有任何错误或警告?

提前感谢!

这样做是不正确的,您有责任正确使用该属性。

请看这个例子:

static __attribute__((pure)) int impure_function(int x, int y)
{
extern int a;
a++;
return x + y;
}
void caller()
{
impure_function(1, 1);
}

GCC(带-O1)为函数caller生成的代码为:

caller():
ret

如您所见,impure_function调用已被完全删除,因为编译器将其视为"纯"。

如果 GCC 看到函数的定义,它可以在内部自动将函数标记为"纯":

static __attribute__((noinline)) int pure_function(int x, int y)
{
return x + y;
}
void caller()
{
pure_function(1, 1);
}

生成的代码:

caller():
ret

因此,在编译器可见的函数上使用此属性是没有意义的。当定义不可用时,例如,当在另一个 DLL 中定义函数时,应该使用它。这意味着当它在适当的位置使用时,编译器无论如何都无法执行健全性检查。因此,实现警告不是很有用(尽管并非毫无意义)。

我认为没有什么可以阻止GCC开发人员实施这样的警告,除了必须花费的时间。

纯函数是优化编译器的提示。也许,当你只传递-O0时,gcc并不关心纯函数(默认优化)。因此,如果f是纯的(并且在翻译单元之外定义,例如在某些外部库中),GCC 编译器可能会y = f(x) + f(x);优化为类似

{ 
int tmp = f(x); /// tmp is a fresh variable, not appearing elsewhere
y = tmp + tmp;
}

但是如果f不是纯粹的(这是通常的情况:想想f调用printfmalloc),则禁止进行此类优化。

sinsqrt这样的标准数学函数是纯粹的(除了IEEE舍入模式的疯狂,请参阅 http://floating-point-gui.de/和Fluctuat了解更多信息),并且它们足够复杂,可以计算以使此类优化值得。

您可以使用gcc -O2 -Wall -fdump-tree-all编译代码,以猜测编译器内部发生的情况。您可以添加-fverbose-asm -S标志以获取生成的*.s汇编程序文件。

您还可以阅读比斯蒙报告草案(特别是其§1.4部分)。它可能会给出一些与您的问题相关的直觉。

在你的特殊情况下,我猜gcc正在内联你的电话;然后纯度就不那么重要了。

如果你有时间,你可以考虑编写自己的GCC插件来发出这样的警告。您将花费数月时间编写它!这些旧幻灯片可能仍然对您有用,即使详细信息已过时。

在理论层面上,要注意赖斯定理。其结果是,纯函数的完美优化可能是不可能的。

请注意位于孟买的海湾合作委员会资源中心。

相关内容

  • 没有找到相关文章

最新更新