[英]pure/const function attributes in different compilers
pure是一个函数属性,表示函数不会修改任何全局内存。
const是一个函数属性,表示函数不读取/修改任何全局内存。
鉴于这些信息,编译器可以做一些额外的优化。
海湾合作委员会的例子:
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)); }
在该示例中,编译器可以将函数计算优化为:
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 或其他编译器)标记函数?
通常,似乎几乎所有编译器都支持GCC属性。 到目前为止,MSVC是唯一不支持它们的编译器(也没有任何替代方案)。
首先,注意“const”是“纯”的更严格版本是有用的,因此如果编译器没有实现“const”,那么“pure”可以用作后备。
正如其他人提到的那样,MSVC并没有真正有类似的东西,但很多编译器都采用了GCC语法,包括许多没有定义__GNUC__
语法(有些有时会做,有时也不做,取决于标志)。
__has_attribute(pure)
和__has_attribute(const)
来检测它们,但是依靠clang设置__GNUC__
可能很好。 这还包括基于clang的编译器,如emscripten和XL C / C ++ 13+。 __TI_GNU_ATTRIBUTE_SUPPORT__
)支持。 其中,clang总是定义__GNUC__
和朋友(目前为4.2,IIRC)。 英特尔默认定义__GNUC__
__(虽然它可以用-no-gcc抑制),就像在C ++模式下PGI一样(但不能在C模式下)。 您需要手动检查的其他人。
Oracle Developer Studio也支持编译指示,因为它被称为Forte Developer 6 。 它们的使用方式略有不同,因为它们要求您指定函数名称:
/* pure: */
#pragma does_not_write_global_data (funcname)
/* const; SPARC-only until 12.2 */
#pragma no_side_effect (funcname)
TI 6.0+(至少)支持#pragma FUNC_IS_PURE;
pragma只在C ++模式下。 在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仓库而不是这个答案上,因为我更有可能让它保持最新状态。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.