【问题标题】:Reversing bits and converting binary to decimal in C在C中反转位并将二进制转换为十进制
【发布时间】:2018-07-12 11:17:00
【问题描述】:

我正在构建一个函数,给定一个整数,反转其所有 32 位(包括符号位),将其转换为新整数,然后返回它。我几乎完成了,但我遇到了两个问题:

第 1 部分: 如果我给它测试(15);那么

buffer = 11110000000000000000000000000000,确实是 15,所有位都反转了。

但是如果我给它 test(-15);那么

buffer = 10001111111111111111111111111111,这是不对的,应该是10001000000000000000000000000001(末尾的1是符号位)。所以对于负值,构建我的缓冲区字符串会出错。 我是否应该将其更改为正整数,反转位,并将末尾的位更改为 1或者有没有更简单的方法来构建这个字符串?

第 2 部分:

“answer”,我返回的应该代表这些数字的整数,从来都不是准确的。如果我给它 test(1500) answer = 185,那么它应该是 1000341504。将 32 位二进制数转换为整数的最佳方法是什么?

我的代码:

int test(int var){
   printf("reversing %d:\n", var);
   char buffer[32];
   int i = 0;
   int power = sizeof(var) * 8;
   int answer = 0;

   while(power > 0){

      //check the lowest bit and put a 0 or 1 into the array
      if((var & 1) == 1){
         buffer[i] = '1';
         i++;
      }

      else{
         buffer[i] = '0';
         i++;
      }
      //shift to the next bit
      var>>= 1;
      power--;
   }

   i++;
   buffer[i] = '\0';

   printf("\nbuffer =  %s", buffer);

   //loop through the array in reverse, building the number
   while(i > 0){
      if(buffer[i] == '0'){

         i--;
      }
      else{

         answer += (2 ^ (32 - i));  //here is where I try to add up answer
         i--;
      }
   }
   printf("\nanswer = %d \n\n\n\n", answer);
   return 0;
}

【问题讨论】:

  • -15 在 32 位二进制中为 11111111111111111111111111111110001,在 100011111111111111111111111111111111 中反转;您的代码正确的(至少在这方面)。
  • 等一下,你是不是想用2 ^ (32 - i)2的(32-i)次方^ 是 XOR 运算符。
  • @ScottHunter:用这种方式表示负数是二进制补码,而不是简单的二进制。
  • 这里有一些您可能感兴趣的bit-twiddling tricks
  • @EricPostpischil:没有“简单的二进制”方式来表示负数。

标签: c binary decimal byte bit


【解决方案1】:

您的转换中不正确的部分是:

answer += (2 ^ (32 - i))

2 ^ (32 - i))2 XOR (32 - i),因为 ^ 是 XOR 运算符。

我会这样转换:

unsigned int answer = 0, pow=1;
for(int i = sizeof(buffer) - 1; i >= 0; --i)
{
    int bit = buffer[i] - '0';

    answer += bit * pow;

    pow *= 2;
}

通过向后执行(从 31 到 0),您不必使用 pow 或创建一个 2 次幂的函数。那会给你整数值 你的二进制解释,总是积极的。如果你想要整数值 2-补码二进制:

int answer = 0;
unsigned int pow=1;
for(int i = sizeof(buffer) - 1; i > 0; --i)
{
    int bit = buffer[i] - '0';

    answer += bit * pow;

    pow *= 2;
}

if(buffer[0] == '1')
    answer |= 0x80000000; // setting last bit

或者更通用的解决方案(不关心 answer 是签名还是未签名)

int answer = 0; // or unsigned int answer = 0;
size_t len = strlen(buffer);
for(int i = len - 1; i > 0; --i)
{
    if(buffer[i] == '1')
        answer |= 1 << len - 1 - i;
}

编辑

我还发现您转换为字符串时出错:

char buffer[32];
...
i++;
buffer[i] = '\0';

缓冲区保存 32 个chars,每个位一个。没有空间留给 0-终止字节,还有i++,你正在溢出缓冲区,i 应该是 33,所以你溢出了 2。

如果您不打算将buffer 视为字符串(没有strcpy,没有strcmp, 没有printf),那么您不必存储终止'\0'。除掉 buffer[i] = '\0'; 就是这样。

但是您确实将其打印为字符串,因此您必须将 buffer 声明为

char buffer[33];

并删除i++ 之前的buffer[i] = '\0';

在这种情况下,您还需要将 for 循环更改为

for(i = sizeof(buffer) - 2; i >= 0; --i)

for(i = sizeof(buffer) - 2; i > 0; --i)

strlen(buffer) - 1 而不是sizeof(buffer) - 2(如果你这样做 在另一个函数上进行转换,然后将指针传递给buffer

【讨论】:

  • 哇,看起来很完美!非常感谢,感谢您对 XOR 的解释。我听说过,但直到现在才知道它是什么意思。
  • @Lazarus 我已经更新了我的答案,我在我的代码上发现了一个错误,我已经修复了,我还在你的代码上发现了另一个错误,我在我的答案中解决了这个错误。跨度>
猜你喜欢
  • 2012-12-26
  • 2018-06-24
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-03-24
  • 2019-04-26
  • 2012-01-06
相关资源
最近更新 更多