如果某个函数有指针参数,可以说明(以及为什么)函数可以归因于pure
或const
。
纯函数的一些常见示例是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
是纯粹的,编译器如何知道不使用第一次调用的结果?
在我的情况下,我想将数组传递给纯函数,并仅根据数组计算结果。有人向我保证这没关系,并且当数组中的值发生变化但地址没有变化时,我的函数将被正确调用。
答案 0 :(得分:4)
如果我正确理解了文档,pure
函数可以依赖于内存的值,编译器会在内存发生变化时知道。而且,pure
函数不能改变程序的状态,例如全局变量,它只产生返回值。
在您的示例代码中,memcmp
可以是pure
函数。编译器发现内存在memcmp
的调用之间发生了变化,并且无法重用第一次调用的结果进行第二次调用。
另一方面,memcmp
可以不声明为const
函数,因为它依赖于内存中的数据。
如果是const
,则编译器可以应用更积极的优化。
出于这个原因,将您要实现的函数声明为pure
(但不是const
)似乎是安全的。
答案 1 :(得分:3)
关于纯粹,我们可以从文章Implications of pure and constant functions看到,纯意味着该函数没有副作用,只取决于参数。
因此,如果编译器可以确定参数是相同的,并且内存在后续调用之间没有改变,它可以消除对纯函数的后续调用,因为它知道纯函数没有副作用。
这意味着编译器必须进行分析才能确定纯函数的参数是否可以在它决定消除对相同参数的纯函数的后续调用之前被修改。
该文章的一个例子如下:
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操作。
这个逻辑也适用于一个指针,所以如果编译器可以证明指向的内存没有被修改,那么它就可以消除对pure函数的调用,所以在编译器看到的情况下:
x[1] = 'a';
它无法消除对memcmp
的第二次调用,因为x
指向的内存已更改。