3

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

#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) = %d\n", pure_function(0, 0));
        printf("impure_function(0, 0) = %d\n", impure_function(0, 0));

        return 0;
}

我用 编译了这个程序gcc -O2 -Wall -Wextra,期望impure_function()__attribute__((pure)). 但是,我没有收到任何警告或错误,并且程序也没有问题地运行。

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

提前致谢!

4

2 回答 2

4

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

看这个例子:

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 开发人员实施此类警告,除了必须花费的时间。

于 2019-11-01T15:12:39.890 回答
2

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

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

但是iff不是纯的(这是通常的情况:考虑调用or ),这样的优化是被禁止的。fprintfmalloc

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

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

您还可以阅读Bismon 报告草案(特别是其第 1.4 节)。它可能会提供与您的问题相关的一些直觉。

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

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

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

请注意位于孟买的GCC 资源中心。

于 2019-11-01T15:12:36.180 回答