【问题标题】:__attribute__((const)) vs __attribute__((pure)) in GNU CGNU C 中的 __attribute__((const)) 与 __attribute__((pure))
【发布时间】:2015-05-20 23:42:51
【问题描述】:

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

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

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

【问题讨论】:

标签: c gcc attributes constants gnu


【解决方案1】:

来自documentation for the ARM compiler(基于gcc):

__attribute__((pure))函数属性
很多函数除了返回一个值外没有任何作用,它们的返回值只取决于参数和全局变量。此类功能可能会受到数据流分析并可能被淘汰。

__attribute__((const))函数属性
许多函数只检查传递给它们的参数,除了返回值之外没有任何影响。这是一个比__attribute__((pure)) 严格得多的类,因为不允许函数读取全局内存。如果已知函数仅对其参数进行操作,则可以对其进行常见的子表达式消除和循环优化。

所以,TL;DR:__attribute__((const))__attribute__((pure)) 相同,但不能访问全局变量。

【讨论】:

  • 注意ARM编译器还提供了__pure函数限定符,比pure属性更严格,相当于const属性。
  • 另外值得注意的是 GCC 文档中关于指针参数的注释:Note that a function that has pointer arguments and examines the data pointed to must not be declared const
  • @origo IMO const 如果指针指向只读数据,例如如果是字符串文字。
【解决方案2】:

GCC manuals 中解释了差异。最值得注意的是,const 函数只能使用传入的参数而不使用任何内存,而pure 函数也可以在限制下访问内存:

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

__attribute__ ((pure)) 表示该函数没有副作用,返回的值取决于参数和全局变量的状态。因此,如果参数相同,并且调用者没有做任何事情来改变调用之间的全局变量的状态,优化器可以安全地忽略对它的一些调用。

__attribute__ ((const)) 表示返回值仅是参数的函数,如果任何参数是指针,则指针不得取消引用 .

const 函数始终为 pure

const 函数的示例包括来自<stdlib.h>abs 函数和来自<math.h> 的一些数学函数:sqrtexp 等(尽管它们可能会受到舍入模式的影响)。

pure 的示例,但非 const 函数将是诸如 strlen 之类的函数 - 因为它取消引用传入的指针。

【讨论】:

  • 从优化器的作用来看,纯函数可能无法访问任何全局变量,这些变量的状态可以被纯函数出现的控制流之外的因素改变。因此,映射到设备状态的全局变量,或者可能被另一个线程修改的全局变量,等等。
  • 是的,两者的区别在于,如果调用者确实修改了全局,那么纯函数可以更改其返回值
  • 毕竟属性是给调用者的信号,调用者无法知道所有内存映射变量存在的状态:D
  • 新措辞:“并且调用者在调用之间没有做任何事情来改变全局变量的状态。”
  • Argh 链接 b0rken。 @Omnifarious 显然它最近发生了变化,比我写答案的时间要好得多; this is the one from the time I was answering the question
【解决方案3】:

请注意,如果一个函数被传递一个指针并检查该指针的上下文,它不能被声明为const,即使传递的指针和指针上下文是const。这是对const 有用性的严重限制。

您可以使用结构在 C 中返回多个值,这使得使用pure 更加容易。 (更典型的是使用指针返回操作数,但这会破坏pure 的使用。

【讨论】:

    猜你喜欢
    • 2019-11-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-04-23
    • 2021-09-21
    • 2012-03-15
    • 1970-01-01
    • 2013-08-31
    相关资源
    最近更新 更多