【问题标题】:How to bit shift "x" with "y"?如何用“y”位移“x”?
【发布时间】:2020-10-26 15:41:36
【问题描述】:

我在使用移位程序时遇到了一些问题。

挑战是编写一个程序,它可以将无符号整数向左移动数步。两个整数都由用户输入。因此,给定两个整数(xy),x 中的位应向左移动y 步,而左侧丢失的位应向右移动。即,在最高有效位之外丢失的位被放置在最低有效位。

为了解决这个挑战,我做了以下尝试:

#include <stdio.h>
#include <utility.h>

unsigned int bitshift(unsigned int a, unsigned int b)
{
    a<<b;
    b>>a;
    return a,b; 
}

int main (void) 
{
    unsigned int x, y;
    
    printf("Enter two integers (smaller than 32) please:\n");
    scanf("%u%u", &x, &y);
    printf("Your integers are %u and %u.\n", x, y);
    printf("In hexadecimal-format, your integers are %08x and %08x.\n", x, y); 
 
    printf("We are now going to perform a bit shift operation\n");
    printf("The result of the bitshift operation is:\n");
    printf("%u and %u\n", bitshift(x,y));
    printf("In hexadecimal: %08x and %08x\n", bitshift(x,y));
    
    while(!KeyHit()); 
    return 0; 
    
}

但是,我在编译时收到一条错误消息,例如“没有足够的参数”,我不明白。

但我最想知道的是bitshift 函数是否可以完成这项工作?

【问题讨论】:

  • return a, b; 等价于return b;。见stackoverflow.com/questions/52550/…
  • a&lt;&lt;b 不会修改 a
  • 错误信息是因为你的格式字符串有两个占位符,但你只给了一个值来格式化。
  • 顺便说一句:更适合您的函数的名称是 rotatebits
  • 为什么你认为bitshift()首先需要返回两个值?它应该只返回a的移位值,不需要更改b

标签: c bit-manipulation bit


【解决方案1】:

这是对Barmar(现已删除)函数bitshift 解决方案的修改,并在 cmets 中提出了改进建议。

不幸的是,C 没有像 CPU 的指令集中那样有操作符来循环一个值中的位。这就是为什么可以通过将最低有效位向左移动,将最高有效位向右移动并组合结果来完成操作的原因。

要计算右移最高有效位的移位宽度,必须使用sizeof 计算数据类型中的位数。

请注意,大于或等于值中位数的移位宽度是未定义行为 (UB)。这就是为什么移位宽度是以值中的位数为模来计算的。此外,左移 0 会导致 UB 右移。

#include <stdio.h>
// get CHAR_BITS to make code portable for unusual platforms
#include <limits.h>

unsigned int bitshift(unsigned int a, unsigned int b)
{
    // modulo operation to prevent undefined behavior
    b %= sizeof a * CHAR_BIT; // sizeof a * 8 on usual platforms
    // prevent undefined behavior for right shift
    if(b == 0) return a;

    unsigned int upper = a << b;
    // not portable for unusual platforms
    // unsigned int lower = a >> (sizeof a * 8 - b);
    unsigned int lower = a >> (sizeof a * CHAR_BIT - b);
    
    return upper | lower;
}

int main (void) 
{
    unsigned int x, y;
    
    printf("Enter two integers (smaller than 32) please:\n");
    scanf("%u%u", &x, &y);
    printf("Your integers are %u and %u.\n", x, y);
    printf("In hexadecimal-format, your integers are %08x and %08x.\n", x, y); 
 
    printf("We are now going to perform a bit shift operation\n");
    printf("The result of the bitshift operation is:\n");
    printf("%u\n", bitshift(x,y));
    printf("In hexadecimal: %08x\n", bitshift(x,y));
    
    return 0; 
    
}

输入/输出示例:

Enter two integers (smaller than 32) please:
1234567890 12
Your integers are 1234567890 and 12.
In hexadecimal-format, your integers are 499602d2 and 0000000c.
We are now going to perform a bit shift operation
The result of the bitshift operation is:
1613571225
In hexadecimal: 602d2499
Enter two integers (smaller than 32) please:
246 28
Your integers are 246 and 28.
In hexadecimal-format, your integers are 000000f6 and 0000001c.
We are now going to perform a bit shift operation
The result of the bitshift operation is:
1610612751
In hexadecimal: 6000000f

【讨论】:

    【解决方案2】:

    右移足以得到将被移出的位,或者它的值左移。为避免 UB,应检查位数。

    unsigned rol(unsigned val, unsigned nbits)
    {
        if(nbits && nbits < CHAR_BIT * sizeof(val))
        {
            val = (val >> (CHAR_BIT * sizeof(val) - nbits)) | (val << nbits);
        }
        return val;
    }
    

    【讨论】:

      【解决方案3】:

      您实际上想要旋转位。

      // Rotate the bits of a by b to the left and return the result
      
      unsigned int bitshift(unsigned int a, unsigned int b)
      {
        for (unsigned int i = 0; i < b; i++)
        {
          unsigned int lowbit = 0;
          if (a & 0x80000000)
            lowbit = 1;
      
          a <<= 1;
          a |= lowbit;
        }
      
        return a;
      }
      

      这假设 unsigned int 是 32 位。您应该能够将其调整为 64 位。

      免责声明:

      虽然这是一种非常幼稚的方法。如果你需要速度,你应该避免循环。这可以做到,但比较棘手。

      【讨论】:

      • 为什么要假设什么?为什么这么复杂?
      • @P__J__ 我写道这是一种非常幼稚的方法。所以没有真正的理由拒绝它(对不起,如果你没有 dv,我赞成你的答案。)
      • IMO 对于 30k+ 用户来说,这是一个非常低质量的答案
      • @P__J__ 不过还是很有教育意义的。
      • 我宁愿说反教条。或者作为一个负面的例子:如何不实现它。
      猜你喜欢
      • 2021-10-11
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-10-17
      • 1970-01-01
      • 2013-04-06
      • 2016-12-27
      相关资源
      最近更新 更多