我怎样才能重写这个if-else语句,以便它不使用跳转?

时间:2011-04-18 10:25:29

标签: c if-statement

我不是要优化任何东西,所以请不要告诉我,过早的优化是万恶之源。我正在尝试解决问题,但我找不到第三种解决方案。

问题是这样的:

if (x)
    y = a;
else
    y = b;

x只能是0或1.如何写这个条件没有跳转?

一种具有数据结构的解决方案是:

int temp[2] = {b, a};
y = temp[x];

另一种算术解决方案是:

y = x * a + (1 - x) * b;

应该有第三个,一个逻辑解决方案。你知道它的样子吗?请在C中提供解决方案。

10 个答案:

答案 0 :(得分:9)

y = a ^ ((x - 1U) & (a ^ b));

这使用按位x-或

答案 1 :(得分:4)

您是说您不想跳转代码或CPU级别?

在我的编译器上

int choose(int x, int a, int b)
{
    int y;

    if (x)
        y = a;
    else
        y = b;

    return y;
}

编译到这个 -

test    ecx, ecx
cmovne  r8d, edx
mov eax, r8d
ret 0

虽然我在C代码级别编写了一个跳转,但生成的机器代码中没有一个,因为编译器能够使用条件移动指令。

答案 2 :(得分:2)

这可能不是最好的解决方案,但我认为它是没有跳跃的按位等价物:

y = (~(x*UINT_MAX) & a) | (~(1 - x) & b);

答案 3 :(得分:0)

以下代码使用的技巧是,当x为1或0时,x-1为0或-1(a.k.a. 0xFFFFFFFF,假设32位int:s)。如果x为1,则&的结果为零,因此结果为a。当x为零时,&的结果将为b-a,则总结果将为a+(b-a)b

int test(int x, int a, int b)
{
  return a + ( (((unsigned int)x)-1) & (b - a) );
}

在一个虚构的微控制器上(没有任何花哨的条件移动指令),这将导致四条指令:

ADD   #-1 R12
SUB   R13, R14
AND   R14, R12
ADD   R13, R12

不可否认,这与@ 6502发布的XOR解决方案非常相似。

答案 4 :(得分:0)

那么选择函数呢?

#include <stdio.h>

int choose(unsigned int x, int a, int b)
{
    unsigned int selector = -x;    

    return (a & selector) | (b & ~selector);
}

int main()
{
    printf("%d\n", choose(0, 123, 200));
    printf("%d\n", choose(1, 123, 200));
}

答案 5 :(得分:0)

使用三元?:运算符。它是为此而制造的。

答案 6 :(得分:0)

我同意Jens;一个三元运算符可以在没有跳跃的情况下完成这个技巧。

y = x ? a : b
顺便说一下,有一个姊妹网站Code Golf,人们在那里提出问题“如何在保持约束条件的同时用最短的代码解决问题x?”

答案 7 :(得分:0)

对于允许条件执行语句的处理器:

y = a;
if (x != 0) y = b;

在32位模式的ARM处理器上,这应该转换为以下伪指令:

mov y, a; move a into y.
test x; (or XOR X, X ; to set condition codes)
MOVNZ y, b ; move b into y if condition is non-zero.

此处不涉及跳转,至少在汇编语言级别。

注意:特定于平台的解决方案可能对没有条件指令执行功能的处理器有效。

答案 8 :(得分:-1)

switch (x) {
   case 1:
      y = a;
      break;
   default:
      y = b;
      break;
}

编辑:原始问题说“有跳”......不是“没有”

答案 9 :(得分:-3)

编辑:我误读了一个问题,即C代码根本不应该使用跳转。

我想我会选择

y = b;
if (x)
    y = a;

如果我正确阅读以下反汇编代码,则应该只有一次跳转:

0000000000400474 <main>:
  400474:   55                      push   %rbp
  400475:   48 89 e5                mov    %rsp,%rbp
  400478:   8b 45 fc                mov    -0x4(%rbp),%eax
  40047b:   89 45 f8                mov    %eax,-0x8(%rbp)
  40047e:   83 7d f4 00             cmpl   $0x0,-0xc(%rbp)
  400482:   74 06                   je     40048a <main+0x16>
  400484:   8b 45 f0                mov    -0x10(%rbp),%eax
  400487:   89 45 f8                mov    %eax,-0x8(%rbp)
  40048a:   c9                      leaveq
  40048b:   c3                      retq
  40048c:   90                      nop
  40048d:   90                      nop
  40048e:   90                      nop
  40048f:   90                      nop