If语句与函数指针

Dav*_*rin 9 c performance if-statement function-pointers data-oriented-design

目标是更改事件循环中的行为,具体取决于是否打开或关闭复选框.我能想到的最简单的方法就是每次运行循环时测试复选框状态.

// if-statement

void action() { /* ... */ }


void someLoop() {

  if (checkboxTrue) {
    action();
  }
  // ... other stuff

}
Run Code Online (Sandbox Code Playgroud)

如果使用函数指针,代码是否会更高效,更清晰或更好?像这样:

// function pointer

void action() { /* ... */ }
void empty() {}
void (*actionPtr)();


void checkboxChanged(int val) {

  if (val == 1)
    actionPtr = &realAction;
  else
    actionPtr = ∅

}

void someLoop() {

  (*actionPtr)();
  // ... other stuff

}
Run Code Online (Sandbox Code Playgroud)

cma*_*ter 10

  1. 一个间接函数调用比一个条件更昂贵.

  2. 如果条件比间接函数调用更昂贵,则有几个.

  3. 在这一点上担心速度是没有意义的:
    你正在等待用户的延迟,你正在处理他可以看到的东西(即不会有大量的复选框).在这样的详细级别上优化每秒执行不到一百万次的代码是绝对没有意义的.

所以,我的建议是:if在编写用户界面时,不要担心函数或函数调用的成本.只考虑耗费时间的算法中的这些东西.

但是,如果您发现内部循环中确实使用了复杂if/ else梯形和/或switch语句,则可以通过使用间接函数调用替换它们来进行优化.


编辑:
你说你每秒有600次检查.假设你只有一个if案例要处理(情况if更快),你不使用函数指针间接"每秒约"6微秒,这是运行时的0.0006%.绝对不值得努力......

  • @VladLazarenko只有正确预测它们.一个函数调用需要10到20个周期,一个缓存的内存访问是4个周期的延迟,间接调用是14到24个周期,忽略了预加载函数指针的可能性,这会再次降低这个数字.由于分支错误预测导致的两次管道冲洗应该至少同样昂贵. (4认同)
  • 如果条件可能仍然比一个间接调用快,则有几个.在最近的Intel CPU上,一个间接调用在性能方面相当于~3到4(if)分支. (3认同)

old*_*mer 5

没有条件分支显然会节省一些时间,当然它只是围绕一个分支进行分支,因此您需要进行管道刷新,这可能是两次刷新而不是一次(当然,除非处理器优化)加上额外的代码做比较.

extern void fun0 ( unsigned int );
extern void fun1 ( unsigned int );

void (*fun(unsigned int));


void dofun0 ( unsigned int x, unsigned int y )
{
    if(x) fun0(y);
    else  fun1(y);
}

void dofun ( unsigned int y )
{
    fun(y);
}
Run Code Online (Sandbox Code Playgroud)

例如,给出这样的东西

Disassembly of section .text:

00000000 <dofun0>:
   0:   e3500000    cmp r0, #0
   4:   e92d4008    push    {r3, lr}
   8:   e1a00001    mov r0, r1
   c:   1a000002    bne 1c <dofun0+0x1c>
  10:   ebfffffe    bl  0 <fun1>
  14:   e8bd4008    pop {r3, lr}
  18:   e12fff1e    bx  lr
  1c:   ebfffffe    bl  0 <fun0>
  20:   e8bd4008    pop {r3, lr}
  24:   e12fff1e    bx  lr

00000028 <dofun>:
  28:   e92d4008    push    {r3, lr}
  2c:   ebfffffe    bl  0 <fun>
  30:   e8bd4008    pop {r3, lr}
  34:   e12fff1e    bx  lr
Run Code Online (Sandbox Code Playgroud)

如果您仔细制作测试,您应该能够衡量性能差异.这将是一个非常小的差异,但绝对可以衡量.