【问题标题】:How to declare and define a pure function in gcc?如何在 gcc 中声明和定义纯函数?
【发布时间】:2015-04-08 22:33:37
【问题描述】:

GCC 具有 pure 和 const 属性,其中 const 实际上用于真正的纯函数(pure 用于idempotent functions which are also side-effect free)。

那么如何使用 const 属性声明和定义函数?

编辑:我对真正的纯函数感兴趣,即使用 const 属性声明的函数,而不是使用纯属性声明的函数。

【问题讨论】:

    标签: c++ gcc


    【解决方案1】:

    例子:

    // Declaration:
    int square (int x) __attribute__ ((const));
    // Definition:
    int __attribute__ ((const)) square (int x)
    { 
        return x*x; 
    }
    

    所有属性的语法几乎相同:__attribute__ (( <attribute-name> ))__attribute__ (( <attribute-name> ( <attribute-options> ) ))。引用您链接到的文档:

    关键字__attribute__ 允许您在进行声明时指定特殊属性。此关键字后跟双括号内的属性说明。

    您链接到的文档中有几个其他属性的示例,包括pure

    int square (int) __attribute__ ((pure));
    

    因此,从语法上讲,使用const 所需的只是将pure 更改为const

    int square (int) __attribute__ ((const));
    

    正如 cmets 中所指出的:如果您在定义中使用它,那么您需要将 __attribute__ ((const)) 放在不同的位置:

    int square (int) __attribute__ ((const)) { ... } // doesn't work
    int __attribute__ ((const)) square (int) { ... } // does work
    

    constpure 属性仅在应用于外部声明时才有用,所以这应该不是问题。如果定义是可见的,GCC 通常能够在没有你帮助的情况下确定函数是否可以被视为const/pure

    【讨论】:

      【解决方案2】:

      根据this article,语法与@hvd 所说的匹配:

      int square (int) __attribute__ ((pure));
      

      但是,当我编译以下示例时,gcc 似乎没有强制执行不检查全局状态的属性。

      #include <stdio.h>
      
      int square (int) __attribute__ ((pure));
      
      int outerX = 7;
      int square(int x) {
         return outerX * x; 
      }
      
      int main(){
          printf("%d\n", square(5));
          return 0;
      }
      

      以下打印没有错误,代码运行并产生35

      gcc -Wall -Werror -pedantic -O3 Pure.c
      
      
      gcc --version
      gcc (Ubuntu/Linaro 4.8.1-10ubuntu9) 4.8.1
      

      更奇怪的是,gcc 也不关心我们是否会改变函数内部的全局状态并在每次调用时返回不同的值,因为它会导致全局状态发生变化。

      #include <stdio.h>
      
      int square (int) __attribute__ ((pure));
      
      int outerX = 7;
      int square(int x) {
         outerX++;
         return outerX * x; 
      }
      
      int main(){
          printf("%d\n", square(5));
          printf("%d\n", square(5));
          printf("%d\n", square(5));
          return 0;
      }
      

      输出:

      40
      45
      50
      

      【讨论】:

      • 是的,文档有点误导,我认为:函数是否纯取决于它的作用,而不是它的作用方式。如果一个函数是纯的,即使它读取全局变量(例如,因为这些变量永远不会改变),那么它可以被声明为纯的。因此,编译器无法强制执行该属性。
      • @hvd,查看我的编辑。我开始怀疑该属性是否有任何作用。
      • “我开始怀疑该属性是否有任何作用。” hvd 在他的回答中建议它可能只会在用于外部函数时覆盖编译器分析...或许可以解释为什么它似乎没有在您的变异测试中发挥作用。
      • @tonyd 即使有外部声明,我也无法生成一个导致编译器警告的示例。
      • @merlin2011 是的,如果函数被内联,优化器将无法再看到属性。此外,printf 可能会修改全局状态,而pure 函数可能依赖于全局状态,因此也会强制进行另一个调用。对于__attribute__((const))-O,但不是-O2,我确实看到40 打印了三次。
      【解决方案3】:

      从 C++11 开始,可以使用 attribute specifier sequence 来指定此类属性。例如:

      [[ gnu::const ]]
      int square (int x)
      { 
          return x * x; 
      }
      

      此外,从 C++17 开始,编译器未知的所有属性都会被忽略而不会导致错误。所以上面的代码可以在不同的编译器和平台之间移植。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2019-07-28
        • 1970-01-01
        • 2013-03-13
        • 1970-01-01
        • 2014-01-17
        • 1970-01-01
        • 1970-01-01
        • 2018-11-09
        相关资源
        最近更新 更多