GNU C中的__attribute__((const))和__attribute__((pure))有什么区别?

54

在GNU C中,__attribute__((const))__attribute__((pure))有什么区别?

__attribute__((const)) int f() {
    /* ... */
    return 4;
}

对比

__attribute__((pure)) int f() {
    /* ... */
    return 4;
}

7
这里可能会有帮助。链接 - haccks
1
请参阅LWN上的纯函数和常量函数的影响 - jww
3个回答

49

根据基于gcc的ARM编译器文档

__attribute__((pure)) 函数属性
许多函数除返回值外没有其他影响,它们的返回值仅取决于参数和全局变量。这些函数可能会接受数据流分析并被消除。

__attribute__((const)) 函数属性
许多函数只检查其传递的参数,并且除了返回值之外没有其他影响。这是比__attribute__((pure))更严格的类别,因为不允许函数读取全局内存。如果已知函数仅对其参数进行操作,则可以将其用于公共子表达式消除和循环优化。

因此,简而言之:__attribute__((const))__attribute__((pure))相同,但不能访问全局变量。


4
请注意,ARM编译器还提供了“__pure”函数限定符,它比“pure”属性更严格,并且相当于“const”属性。 - ysap
10
值得注意的是GCC文档中有关指针参数的注释:需要注意的是,如果一个函数有指针参数并且检查所指向的数据,则不能声明为const。 - origo
1
在我看来,如果指针指向只读数据,例如字符串字面量,则使用const可能是可以的。 - rockdaboot

41
区别在于GCC手册中有所解释。特别要注意的是,const函数只能使用传递进来的参数而不能使用任何内存,而pure函数也可以访问内存,但有限制:

pure属性禁止函数修改程序状态,这种状态可以通过除了检查函数的返回值之外的方式来观察到。但是,使用pure属性声明的函数可以安全地读取任何非易失性对象,并以不影响其返回值或程序的可观测状态的方式修改对象的值。

__attribute__ ((pure))意味着该函数没有副作用,返回的值取决于参数和全局变量的状态。因此,如果参数相同且调用者没有对全局状态进行更改,则优化器可以省略其中一些调用。 __attribute__ ((const))意味着返回值完全是由参数决定的,并且如果任何参数是指针,则不能对指针进行间接引用。 const函数始终是pure函数。 <stdlib.h>中的abs函数和<math.h>中的一些数学函数如sqrt, exp等都是const函数的例子(尽管它们可能受到舍入模式的影响)。 strlen等函数因为对传递进来的指针进行了间接引用,所以是pure但非函数的例子。

从优化器的行为来看,纯函数可能不会访问任何全局变量,这些变量的状态可能会受到出现在纯函数控制流之外的因素的影响。因此,映射到设备状态的全局变量或可能被另一个线程修改的变量等都属于此类。 - Omnifarious
毕竟属性是给调用者的一个信号,而调用者无法知道所有存在的内存映射变量的状态 :D - Antti Haapala -- Слава Україні
"并且调用者在调用之间没有做任何改变全局状态的操作。" - Antti Haapala -- Слава Україні
我认为借鉴文档并说“如果函数访问易失变量,则该函数不是纯函数”会更好。 - Omnifarious
1
链接坏了。@Omnifarious 显然最近有很大改变,现在比我写答案时好多了;这是我回答问题时的链接 - Antti Haapala -- Слава Україні
显示剩余4条评论

3
请注意,如果一个函数接收了一个指针并且检查该指针的上下文,那么即使传递的指针和指针的上下文是const的,在声明时它也不能被声明为“const”。这是对“const”实用性的严重限制。
在C语言中可以通过使用结构体来返回多个值,这样更容易使用“pure”(纯函数)。尽管使用指针返回操作数更为常见,但这会破坏“pure”的使用。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接