【问题标题】:GCC pure/const functions that accept a pointer argument接受指针参数的 GCC 纯/常量函数
【发布时间】:2015-07-09 01:51:53
【问题描述】:

有人可以澄清一下函数是否(以及为什么)可以归因于pureconst(如果它具有指针参数)。

根据GCC documentation

纯函数的一些常见示例是 strlen 或 memcmp。

纯函数的全部意义在于它只需要为相同的参数调用一次,即如果编译器认为它适合这样做,结果可以被缓存,但是这对 memcmp 是如何工作的?

例如:

char *x = calloc(1, 8);
char *y = calloc(1, 8);

if (memcmp(x, y, 8) > 0)
    printf("x > y\n");

x[1] = 'a';
if (memcmp(x, y, 8) > 0)
    printf("x > y\n");

第二次调用memcmp的参数和第一次相同(指针指向同一个地址),如果memcmp是纯的,编译器怎么知道不使用第一次调用的结果?

在我的例子中,我想将一个数组传递给一个纯函数,并仅根据数组计算结果。有人向我保证,这没关系,当数组中的值发生变化但地址没有变化时,我的函数将被正确调用。

【问题讨论】:

    标签: c++ c pointers gcc


    【解决方案1】:

    如果我正确理解了文档,pure 函数可以依赖于内存的值,编译器知道内存何时发生变化。而且pure函数不能改变程序的状态,比如全局变量,它只会产生一个返回值。

    在您的示例代码中,memcmp 可以是 pure 函数。编译器看到在对memcmp 的调用之间内存发生了变化,并且无法将第一次调用的结果用于第二次调用。

    另一方面,memcmp 可以声明为const 函数,因为它依赖于内存中的数据。 如果是const,编译器可以应用更积极的优化。

    因此,将要实现的函数声明为pure(但不是const)似乎是安全的。

    【讨论】:

      【解决方案2】:

      关于pure我们从Implications of pure and constant functions一文中可以看出pure的意思是函数没有副作用,只依赖于参数。

      因此,如果编译器可以确定参数相同,并且在后续调用之间内存没有改变,它可以消除对纯函数的后续调用,因为它知道纯函数没有副作用。

      这意味着编译器必须进行分析,以确定纯函数的参数是否可以被修改,然后才能决定消除对相同参数的纯函数的后续调用。

      文章中的一个例子如下:

      int someimpurefunction(int a);
      int somepurefunction(int a)
        __attribute__((pure));
      
      int testfunction(int a, int b, int c, int d) {
      
        int res1 = someimpurefunction(a) ? someimpurefunction(a) : b;
        int res2 = somepurefunction(a) ? somepurefunction(a) : c;
        int res3 = a+b ? a+b : d;
      
        return res1+res2+res3;
      }
      

      它显示了生成的优化程序集,显示 somepurefunction 只被调用了一次,然后说:

      如你所见,纯函数只被调用一次,因为三元运算符中的两个引用是等价的,而另一个被调用了两次。 这是因为在两次纯函数调用之间编译器已知的全局内存没有变化(函数本身无法更改它 - 请注意,编译器永远不会将多线程带入帐户,即使通过 -pthread 标志显式请求它),而允许非纯函数更改全局内存或使用 I/O 操作。

      这个逻辑也适用于指针,所以如果编译器可以证明指向指针的内存没有被修改,那么它可以消除对纯函数的调用,所以在编译器看到的情况下:

      x[1] = 'a';
      

      它无法消除对memcmp 的第二次调用,因为x 指向的内存已更改。

      【讨论】:

      • 感谢文章链接,很有趣。但我的问题专门针对纯函数的指针参数。
      • 那么如果在编译时不知道 8 和 1 会发生什么?例如。它们是可变的?
      • @kata:如果编译器不能证明内存没有被变异,它必须假设它可能已经发生了。所以它不会执行(不安全的)优化。
      • 好的,现在很清楚了。这个答案应该被接受:)
      • 如果您在最后添加一小部分解释相同的逻辑适用于指针,我会接受这个答案(我只是想确保人们通过谷歌登陆这里而不阅读这些 cmets 觉得他们的问题是已回答)
      猜你喜欢
      • 2013-06-06
      • 1970-01-01
      • 2021-12-08
      • 2011-03-27
      • 1970-01-01
      • 1970-01-01
      • 2011-07-03
      • 2020-04-27
      相关资源
      最近更新 更多