接受指针参数的GCC纯/const函数

GCC pure/const functions that accept a pointer argument

本文关键字:const 函数 GCC 指针 参数      更新时间:2023-10-16

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

根据GCC文档:

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

一个纯函数的要点是,它只需要调用一次相同的参数,也就是说,结果可以缓存,如果编译器认为它适合这样做,但是这是如何工作的memcmp?

例如:

char *x = calloc(1, 8);
char *y = calloc(1, 8);
if (memcmp(x, y, 8) > 0)
    printf("x > yn");
x[1] = 'a';
if (memcmp(x, y, 8) > 0)
    printf("x > yn");

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

在我的例子中,我想将一个数组传递给一个纯函数,并仅基于数组计算结果。有人向我保证,这是可以的,当数组中的值改变,但地址没有,我的函数将被正确调用。

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

在您的示例代码中,memcmp可以是pure函数。编译器看到在调用memcmp之间内存被改变了,并且不能在第二次调用时重用第一次调用的结果。

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

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

关于纯函数,我们可以从纯函数和常量函数的含义一文中看到,纯函数意味着函数没有副作用,只依赖于参数。

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

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

文章中的一个例子如下:

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所指向的内存已经改变。