【问题标题】:Using flags with logical operators instead of conditional statements (Such as if())使用带有逻辑运算符的标志而不是条件语句(例如 if())
【发布时间】:2012-10-22 17:14:15
【问题描述】:

假设我想在设置标志时更改变量的值。一个明显的方法如下。

int a = 1, b = 2;
if(Flag)
    {
    a=b;
    Flag = false;
    }

然而,WRT 为执行操作而生成的代码效率非常低。我发现执行该操作的代码减少了 40%。

a = ((!Flag)*a)+((Flag)*b);
Flag = false;

我的问题:我宁愿不使用乘法“*”运算符,因为乘法/除法运算符在我的目标上执行速度较慢。在不增加代码空间的情况下,我还能用什么来加快速度?

编辑: 目标设备是运行在 kHz 范围内的 MSP430。代码空间和执行时间至关重要。编译器是 IAR C

【问题讨论】:

  • Flagfalse 时,a = ((!Flag)*a)+((Flag)*b); 不会以不必要的a=a 分配结束吗?你不想使用条件来避免这种情况吗?
  • @Mike 是的,但是生成的代码仍然比使用条件时要少。
  • ::face palm:: 不要。只是,不要。使用好的编译器并让它进行优化。 It is almost certainly better at it then you are 和人们(包括你未来的自己)将能够阅读你的代码。请注意上面写着 “gcc 在所有平台上都比视频编解码器程序员更聪明”的部分。(第 41 页)
  • @dmckee 编译器是 IAR C。我可以向你保证,这是一个非常好的(且昂贵的)编译器。
  • int b = 2, a = Flag ? b : 1; Flag = false; 怎么样?

标签: c optimization flags logical-operators


【解决方案1】:

以下内容无需使用乘法或任何条件即可实现您想要的逻辑:

unsigned int mask = Flag-1;
a = (mask & a) | (~mask & b);

所以当 Flag==1 你得到

a = (0x0 & a) | (0xffff & b);

当 Flag==0 你得到

a = (0xffff & a) | (0x0 & b);

(您实际上也不需要单独的掩码变量。您可以使用--Flag 并使用Flag 而不是mask,我只是认为它会使解决方案更清晰一些。)

【讨论】:

  • 我的自我强制规则:不要在同一语句中混合逻辑和二进制算术运算符。我喜欢这个编辑...
  • @hexist 使用 ResetTimeout--; Timeout = (ResetTimeout & CMD_TIMEOUT_INIT) | (~ResetTimeout & Timeout); ResetTimeout = false; 代替 if 语句导致 CODE 空间减少了 68%。
【解决方案2】:

你的编译器能够比这个hack更好地优化你的代码(检查生成的程序集)。除了在比较慢的处理器上(例如 PowerPC),你应该避免它。无论如何,如果您仍然有动力,请参阅here

【讨论】:

    【解决方案3】:

    我会这样写,不考虑微优化:

    int b = 2, a = Flag ? b : 1;
    
    Flag = false;
    

    看看效率如何。

    【讨论】:

    • 这应该生成几乎相同的操作码,只是顺序不同。否则编译器配置不当/坏。
    • 在我的例子中,将 a = ((!Flag)*a)+((Flag)*b) 更改为 a = Flag ? b : a 节省了 10 个字节的 CODE 内存。这比 if 语句减少了 58%。
    • 另外,@KerreckSB a = ((!Flag)*a)+((Flag)*b) 只生成 4 行汇编
    【解决方案4】:

    您的初始代码尽可能有效。如果您能够通过其他一些晦涩的混淆生成更有效的代码,那么您的编译器的优化要么配置不正确,要么写得不好。前者更有可能,但如果是后者,请询问 IAR 为什么他们的编译器会生成错误的代码。不要试图通过编写混淆代码来修复他们的编译器。

    您不需要使用条件 ?: 运算符,它应该生成完全相同的代码。

    此外,我对 MSP430 了解不多,但它平均为 16 位,并且没有任何超高级指令缓存或分支预测,如果你认为它有的话,你只是在自欺欺人。即使有,您仍然不应该混淆您的代码。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2019-08-15
      • 1970-01-01
      • 1970-01-01
      • 2017-01-01
      • 2017-12-04
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多