左侧按位旋转变量而不进位?

时间:2011-04-07 20:36:58

标签: c gcc bitwise-operators inline-assembly

让我们有一个任务是在变量a上进行左位旋转而不用C ++进位。我认为,使用汇编内联执行此例程会好得多,不是吗?

例如,如果我们有a == 100 == 0b<a bunch of zeros>1100100a LR 1应提供0b1001001 == 73(即不是0b11001000 == 200)。

所以,问题是:如何重写下面的代码以适应上述任务?

#include <stdio.h>

int main()
{
  long long a = 0;

  scanf("%ld", &a);

  // Here the left-shifting should be replaced with left-rotating
  printf("%ld\n", a << 1);

  return 0;
}

3 个答案:

答案 0 :(得分:3)

进行内联汇编以执行像left-shift with carry这样简单的操作肯定不会更好。任何现代编译器都可以轻松处理它并为您手写的任何内容生成等效的程序集,并且具有不会变得与平台相关的优势。

答案 1 :(得分:3)

在高级语言(甚至是C)中,Shift-with-carry是没有意义的,因为除了更多的内联汇编之外,没有办法从这些语言中读取进位标志(以前是高位)。

另一方面,如果将高位存储到另一个变量(并且还进行移位操作),编译器可能会生成一个shift-with-carry,然后是add-carry或mov-carry来获取它。编译器在将两条指令组合成乘法加法融合指令方面也相当擅长。


查看修订后的问题,您尝试执行的操作与普通处理器上可用的任何移位指令完全无关。由于您希望逐一移位然后清除最重要的一位,您可能会发现bsr指令很有用,许多编译器都有intrinsic functions,可以让您从C代码中访问该指令。

答案 2 :(得分:1)

如果你真的想要汇编程序,那么这里是如何旋转64位变量一位可能在Visual C ++中看起来(对于GCC __asm是不同的)。为了比较,还有C ++中的实现。当然这是32位汇编程序。

unsigned long long rotate_left_64(unsigned long long n)
{  
    return (n << 1) | (n >> 63);
}

int main()
{
    unsigned long long a = 0xF0F0F0F0F0F0F0F0;

    std::cout << std::hex << rotate_left_64(a) << std::endl;

    __asm
    {
        lea ebx, a
        rol DWORD PTR [ebx], 1
        rcl DWORD PTR [ebx+4], 1
    }
    std::cout << std::hex << a << std::endl;
    return 0;
}