不同编译器中的pure / const函数属性

时间:2010-05-09 15:49:59

标签: c++ gcc const function-attributes

pure 是一个函数属性,表示函数不会修改任何全局内存 const 是一个函数属性,表示函数不会读取/修改任何全局内存。

鉴于该信息,编译器可以进行一些额外的优化。

GCC的例子:

float sigmoid(float x) __attribute__ ((const));

float calculate(float x, unsigned int C) {
    float sum = 0;
    for(unsigned int i = 0; i < C; ++i)
        sum += sigmoid(x);
    return sum;
}

float sigmoid(float x) { return 1.0f / (1.0f - exp(-x)); }

在该示例中,编译器可以将函数 calculate 优化为:

float calculate(float x, unsigned int C) {
    float sum = 0;
    float temp = C ? sigmoid(x) : 0.0f;
    for(unsigned int i = 0; i < C; ++i)
        sum += temp;
    return sum;
}

或者如果您的编译器足够聪明(并且对浮点数不那么严格):

float calculate(float x, unsigned int C) { return C ? sigmoid(x) * C : 0.0f; }

如何为不同的编译器(即GCC,Clang,ICC,MSVC或其他编译器)以这种方式标记函数?

2 个答案:

答案 0 :(得分:28)

通常,似乎几乎所有编译器都支持GCC属性。到目前为止,MSVC是唯一不支持它们的编译器(也没有任何替代方案)。

答案 1 :(得分:4)

首先,注意&#34; const&#34;是一个更严格的版本 &#34;纯粹&#34;,所以&#34;纯粹&#34;如果编译器没有,可以用作后备 实施&#34; const&#34;。

正如其他人所说,MSVC并没有真正有类似的东西, 但很多编译器都采用了GCC语法,包括很多 哪些不定义__GNUC__(有些人有时会这样做 有时候不要,视标志而定。)

  • GCC支持 pure 自2.96+以来 const 从2.5.0开始,如果您想查看版本。
  • Clang支持两者;你可以使用__has_attribute(pure)__has_attribute(const)来检测它们,但它可能很好 只依靠clang设置__GNUC__。这还包括编译器 基于像emscripten和XL C / C ++ 13 +这样的clang。
  • 英特尔C / C ++编译器支持这两者,但他们的文档是 可怕的,所以我不知道什么时候被添加。当然是16.0+ 安全
  • Oracle Developer Studio 12.2+支持两者。
  • ARM C / C ++编译器4.1+(可能更旧)支持两者 pureconst
  • IBM XL C / C ++至少10.1
  • TI 8.0+
  • TI 7.3+ 使用--gcc(使用__TI_GNU_ATTRIBUTE_SUPPORT__检测到)支持两者。
  • PGI没有记录它(AFAICT),但这两个属性都有效(或者是 至少默默地忽略了)。 17.10+是安全的,尽管他们可能是安全的 已经接受了很长时间。

其中,clang总是定义__GNUC__和朋友(目前为 4.2,IIRC)。英特尔默认定义__GNUC__(尽管可以 用-no-gcc抑制)和C ++模式下的PGI一样(但不是用C语言 模式)。您必须手动检查其他人。

Oracle Developer Studio也支持pragma,因为它已知 为Forte Developer 6。他们&#39;再 使用方式略有不同,因为它们要求您指定功能 名:

/* pure: */
#pragma does_not_write_global_data (funcname)
/* const; SPARC-only until 12.2 */
#pragma no_side_effect (funcname)

TI 6.0+(至少)支持C ++中的#pragma FUNC_IS_PURE; pragma 仅模式。在C模式下,它是#pragma FUNC_IS_PURE(funcname);

大部分内容可以隐藏在宏的背后,这就是我所做的 Hedley

#if \
  HEDLEY_GNUC_HAS_ATTRIBUTE(pure,2,96,0) || \
  HEDLEY_INTEL_VERSION_CHECK(16,0,0) || \
  HEDLEY_SUNPRO_VERSION_CHECK(5,11,0) || \
  HEDLEY_ARM_VERSION_CHECK(4,1,0) || \
  HEDLEY_IBM_VERSION_CHECK(10,1,0) || \
  HEDLEY_TI_VERSION_CHECK(8,0,0) || \
  (HEDLEY_TI_VERSION_CHECK(7,3,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \
  HEDLEY_PGI_VERSION_CHECK(17,10,0)
#  define HEDLEY_PURE __attribute__((__pure__))
#elif HEDLEY_TI_VERSION_CHECK(6,0,0) && defined(__cplusplus)
#  define HEDLEY_NO_RETURN _Pragma("FUNC_IS_PURE;")
#else
#  define HEDLEY_PURE
#endif

#if HEDLEY_GNUC_HAS_ATTRIBUTE(const, 2, 5, 0) || \
  HEDLEY_INTEL_VERSION_CHECK(16,0,0) || \
  HEDLEY_SUNPRO_VERSION_CHECK(5,11,0) || \
  HEDLEY_ARM_VERSION_CHECK(4,1,0) || \
  HEDLEY_IBM_VERSION_CHECK(10,1,0) || \
  HEDLEY_TI_VERSION_CHECK(8,0,0) || \
  (HEDLEY_TI_VERSION_CHECK(7,3,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \
  HEDLEY_PGI_VERSION_CHECK(17,10,0)
#  define HEDLEY_CONST __attribute__((__const__))
#else
#  define HEDLEY_CONST HEDLEY_PURE
#endif

这并不包括需要该功能的变体 将名称作为参数,但它仍然涵盖浩大的大多数 用户,在任何地方都可以安全使用。

如果你不想使用Hedley(它是一个公共领域/ CC0标题),它 不应该更换内部版本宏太困难。如果 你选择这样做,你应该把你的端口建立在 Hedley回购代替了这个答案,因为我更有可能保留它 最新的。