不同编译器中的 pure/const 函数属性
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)); }
在该示例中,编译器可以将函数计算优化为:
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 或其他?
pure is a function attribute which says that a function does not modify any global memory.
const is a function attribute which says that a function does not read/modify any global memory.
Given that information, the compiler can do some additional optimisations.
Example for 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)); }
In that example, the compiler could optimise the function calculate to:
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;
}
Or if your compiler is clever enough (and not so strict about floats):
float calculate(float x, unsigned int C) { return C ? sigmoid(x) * C : 0.0f; }
How can I mark a function in such way for the different compilers, i.e. GCC, Clang, ICC, MSVC or others?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
总的来说,似乎几乎所有编译器都支持 GCC 属性。 MSVC 是迄今为止唯一不支持它们的编译器(并且也没有任何替代方案)。
In general, it seems that almost all compilers support the GCC attributes. MSVC is so far the only compiler which does not support them (and which also doesn't have any alternative).
首先,值得注意的是“const”是更严格的版本
“pure”,因此如果编译器不这样做,“pure”可以用作后备
实施“常量”。
正如其他人提到的,MSVC 实际上没有类似的东西,
但是很多编译器都采用了GCC语法,包括很多
没有定义
__GNUC__
(有些有时会定义有时不会,具体取决于标志)。
纯
自 2.96+ 起,以及
常量
从 2.5.0 开始,如果您想检查版本。
__has_attribute(const)
来检测它们,但可能没问题只需依赖 clang 设置 __GNUC__ 即可。这还包括编译器
基于 emscripten 和 XL C/C++ 13+ 等 clang。
太糟糕了,所以我不知道它们是什么时候添加的。 16.0+肯定是
安全的。
纯
和
const
与 --gcc (通过
__TI_GNU_ATTRIBUTE_SUPPORT__
检测)支持两者。至少默默地忽略)。 17.10+ 是安全的,尽管他们可能已经
被接受的时间要长得多。
其中,clang 始终定义
__GNUC__
和朋友(目前为4.2,IIRC)。 Intel 默认定义了
__GNUC__
(尽管它可以是使用 -no-gcc 抑制)就像 C++ 模式中的 PGI 一样(但在 C 中则不然)
模式)。其他的你必须手动检查。
Oracle Developer Studio 自已知以来也支持编译指示
作为 Forte 开发人员
6.。他们是
使用方式有点不同,因为它们要求您指定函数
名称:
TI 6.0+(至少)支持 C++ 中的
#pragma FUNC_IS_PURE;
pragma仅模式。在 C 模式下,它是
#pragma FUNC_IS_PURE(funcname);
。其中大部分可以隐藏在宏后面,这就是我所做的
Hedley:
这不包括需要该函数的变体
名称作为参数,但它仍然涵盖了绝大多数
用户,并且在任何地方都可以安全使用。
如果您不想使用 Hedley(它是单个公共域/CC0 标头)
替换内部版本宏应该不会太困难。如果
如果您选择这样做,您可能应该将您的端口基于
Hedley repo 而不是这个答案,因为我更有可能保留它
最新。
First, it's useful to note that "const" is a more strict version of
"pure", so "pure" can be used as a fallback if a compiler doesn't
implement "const".
As others have mentioned, MSVC doesn't really have anything similar,
but a lot of compilers have adopted the GCC syntax, including many
which don't define
__GNUC__
(and some which sometimes do andsometimes don't, depending on flags).
pure
since 2.96+, and
const
since 2.5.0, in case you feel like checking the version.
__has_attribute(pure)
and__has_attribute(const)
to detect them, but it's probably fine tojust rely on clang setting
__GNUC__
. This also includes compilersbased on clang like emscripten and XL C/C++ 13+.
terrible so I have no idea when they were added. 16.0+ is certainly
safe.
pure
and
const
with --gcc (detected with
__TI_GNU_ATTRIBUTE_SUPPORT__
) supports both.at least silently ignored). 17.10+ is safe, though they've probably
been acceptable for much longer.
Of these, clang always defines
__GNUC__
and friends (currently to4.2, IIRC). Intel defines
__GNUC__
by default (though it can besuppressed with -no-gcc) as does PGI in C++ mode (but not in C
mode). The others you'll have to check for manually.
Oracle Developer Studio has also supported pragmas since it was known
as Forte Developer
6. They're
used a bit differently since they require you to specify the function
name:
TI 6.0+ (at least) supports a
#pragma FUNC_IS_PURE;
pragma in C++mode only. In C mode, it's
#pragma FUNC_IS_PURE(funcname);
.Most of this can be hidden behind a macro, which is what I've done in
Hedley:
This doesn't include the variants which would require the function
names as an argument, but it still covers the vast majority of
users, and it's safe to use everywhere.
If you don't want to use Hedley (it's a single public domain / CC0 header) it
shouldn't be too difficult to replace the internal version macros. If
you choose to do that, you should probably base your port on the
Hedley repo instead of this answer as I'm much more likely to keep it
up to date.
作为多年后阅读本文的任何人的更新,从 C++11 开始(并不断改进 C++14、C++17 和 C++20),
constexpr
关键字已添加到语言中,让您可以标记函数、方法、语句、模板、变量(几乎所有东西)绝对且完全恒定,允许编译器进行良好的优化。constevel
和constinit
也被添加到 C++20 中以进一步扩展编译时间语言的能力。As an update for anyone reading this after all these years, starting with C++11 (and with continuous improvements with C++14, C++17 and C++20), the
constexpr
keyword was added to the language, letting you mark functions, methods, statements, templates, variables (pretty much everything) as absolutely and completely constant, allowing for nice optimization from the compiler.constevel
andconstinit
were also added in C++20 to further expand the compile-time capabilities of the language.