c/c 优化脱离检查以查看是否已经运行了一个函数
C/C++ optimizing away checks to see if a function has already been run before
假设您在C/C 中具有一个函数,这是在第一次运行时以某种方式行为。然后,所有其他时间的行为是另一种方式(例如,请参见下文)。第一次运行后,IF语句变为多余,如果速度很重要,则可以优化。有什么方法可以进行此优化?
bool val = true;
void function1() {
if (val == true) {
// do something
val = false;
}
else {
// do other stuff, val is never set to true again
}
}
gcc
具有内置功能,可让您告知有关分支预测的实现:
__builtin_expect
http://gcc.gnu.org/onlinedocs/gcc/other-builtins.html
例如,在您的情况下:
bool val = true;
void function1()
{
if (__builtin_expect(val, 0)) {
// do something
val = false;
}
else {
// do other stuff, val is never set to true again
}
}
只有在确定它确实是瓶颈的情况下,才应该进行更改。通过分支预测,if
语句可能是即时的,因为它是一个非常可预测的模式。
也就是说,您可以使用回调:
#include <iostream>
using namespace std;
typedef void (*FunPtr) (void);
FunPtr method;
void subsequentRun()
{
std::cout << "subsequent call" << std::endl;
}
void firstRun()
{
std::cout << "first run" << std::endl;
method = subsequentRun;
}
int main()
{
method = firstRun;
method();
method();
method();
}
产生输出:
首次运行
后续呼叫
随后的调用
您可以使用功能指针,但是在任何情况下都需要间接调用:
void (*yourFunction)(void) = &firstCall;
void firstCall() {
..
yourFunction = &otherCalls;
}
void otherCalls() {
..
}
void main()
{
yourFunction();
}
一种可能的方法是编译两个不同版本的函数(这可以通过模板中的源中的一个函数完成),并使用功能指针或对象在运行时决定。但是,除非您的功能真的很昂贵,否则指针开销可能会超过任何潜在的收益。
您可以使用static
成员变量而不是全局变量。
或,如果您要运行的代码第一次更改所有以后用途的内容(例如,打开文件?),则可以使用该更改来确定是否运行代码(即,检查文件是否打开)。这将为您节省额外的变量。另外,它可能有助于检查错误 - 如果由于某种原因,另一个操作将初始更改不变(例如,该文件在可移动的媒体上被不适当地删除),则您的检查可能会尝试重新进行更改。
编译器只能优化编译时已知的内容。
在您的情况下,val
的值仅在运行时已知,因此无法优化。
if
测试非常快,您不必担心优化它。
如果您想使代码有点清洁,则可以使用static
局部变量局部。
void function() {
static bool firstRun = true;
if (firstRun) {
firstRun = false;
...
}
else {
...
}
}
首次输入该函数时,firstRun
是正确的,并且它将持续存在,因此每次调用函数时,firstRun
变量将与之前的实例相同(并且将为每个后续时间为错误)。
这可以与 @ouah的解决方案一起使用。
诸如G (和我敢肯定MSVC)的编译器支持在第一次运行时生成配置文件数据,然后使用该数据更好地猜测最有可能遵循哪些分支,并相应地优化。如果您使用的是GCC,请查看-fprofile-generate
选项。
预期的行为是编译器将优化,如果语句将首先订购,从而避免在所有后续呼叫上进行JMP操作,从而使其速度差不多,就像它不在那儿一样,尤其是尤其是如果您返回其他地方(因此避免了必须跳过"如果"语句)
进行此优化的一种方法是将函数分为二。而不是:
void function1()
{
if (val == true) {
// do something
val = false;
} else {
// do other stuff
}
}
这样做:
void function1()
{
// do something
}
void function2()
{
// do other stuff
}
您可以做的一件事就是将逻辑放入对象的构造函数中,然后将其定义为static
。如果这样的 static
对象发生在块范围中,则该构造器在执行该范围的执行时间内运行。编译器发出曾经的一次检查。
您还可以将static
对象放在文件范围,然后在调用main
之前初始化它们。
我给出了这个答案,因为也许您没有有效利用C 类。
(关于C/C++
,没有这样的语言。有C,并且有C 。您在C中工作是否也必须编译为C (有时是非正式地称为" Clean C"),还是您真的在工作在C ?)
什么是"清洁c&quot"它与标准C?
要保持编译器独立,您可以在一个函数中对if()的零件进行编码,而另一个函数中的 else{}
则可以在另一个函数中进行编码。几乎所有编译器都优化了if() else{}
-因此,一旦最有可能是else{}
-因此,代码if()
中的偶尔可执行代码,其余代码在else
- 无法获取菜单选择以运行函数.C++
- 为什么std::async使用同一个线程运行函数
- MINGW - 正确运行函数所需的 cdecl
- 如何在 C 中使用空的 main() 方法运行函数?
- 运行函数作为 constexpr 和不作为 constexpr
- 如何在全局变量的构造函数之前运行函数
- 在 Cap'n Proto RPC 服务器中定期运行函数
- 为什么当我在 c++ 中运行函数时,我的代码显示数字 53
- CLang:在 std::thread 中运行函数会导致结构创建BAD_ACCESS
- 如何使用 TBB 在单个线程中运行函数
- 我在运行函数 GetVolumeInformation() 时得到非常随机的结果
- 如何使用 boost::asio io_service 运行函数异步
- Qt - 在其他线程上运行函数
- 在一组模板化对象上运行函数
- pybind11:属性错误:尝试从 py 文件运行函数时,模块'XXX'没有属性'YYY'
- 添加按钮以通知运行函数的通知
- 如何在程序后台运行函数(特别是自动保存函数)?QT / C++
- Qt - 在单独的线程中运行函数
- 如何在单独的线程上运行函数(如果线程可用)
- 如何发出编译和运行C++函数的 LLVM IR