在C语言的位运算中,0x01和0x80代表什么?

8
我正在尝试在C语言中反转比特顺序(作业问题,主题:位运算符)。我找到了这个解决方案,但是我对使用的十六进制值——0x01和0x80有些困惑。
  unsigned char reverse(unsigned char c) {
     int shift;
     unsigned char result = 0;

     for (shift = 0; shift < CHAR_BITS; shift++) {
        if (c & (0x01 << shift))
            result |= (0x80 >> shift);
     }
     return result;
  }

我正在使用的书籍没有讨论这些类型的值,所以我不太确定如何处理它们。有人能解释一下这个解决方案吗?谢谢!


代码中的一个奇怪之处是... CHAR_BITS 不是标准定义,而是在 <limits.h> 中定义的 CHAR_BIT - Jonathan Leffler
4个回答

9

0x01代表最低有效位是1,因此十进制值为1。

0x80是8位字节中最高有效位设置为1。如果在带符号的char类型中存储它(在使用2的补码表示法的机器上 - 大多数计算机都是如此),则它是最小的负值(十进制-128);在无符号char类型中,它是十进制+ 128。

另一个成为第二天性的模式是所有位均设置为0xFF;这对于有符号字符是十进制-1,对于无符号字符是255。当然,还有没有任何位设置为0的0x00或零。

循环在第一次循环中所做的是检查LSB(最低有效位)是否设置,如果设置,则在结果中设置MSB(最高有效位)。在下一次循环中,它将检查下一个最低有效位并设置下一个最高有效位,以此类推。

| MSB |     |     |     |     |     |     | LSB |
|  1  |  0  |  1  |  1  |  0  |  0  |  1  |  1  |   Input
|  1  |  1  |  0  |  0  |  1  |  1  |  0  |  1  |   Output
|  1  |  0  |  0  |  0  |  0  |  0  |  0  |  0  |   0x80
|  0  |  0  |  0  |  0  |  0  |  0  |  0  |  1  |   0x01
|  0  |  1  |  0  |  0  |  0  |  0  |  0  |  0  |   (0x80 >> 1)
|  0  |  0  |  0  |  0  |  0  |  0  |  1  |  0  |   (0x01 << 1)

小心。负值仅在整数的补码表示中有效。在反码或符号-幅值中,位模式具有不同的含义。C并没有强制使用二进制补码。 - Steve Emmerson
@Steve:确实如此……我已经相应地调整了答案。 - Jonathan Leffler
1
哇,谢谢你的解释——这个图示真的让我理解了。 - Daniel Szabo
很好的解释! - ks2bmallik

5

每个十六进制数位代表4位二进制数,所以:

  • 0x01就是1的长写法。
  • 0x80是二进制[1000][0000]的简写方式,等同于128。

解决方案是使用位运算符来测试和设置值。

表达式:

if (a & b) { ... }

如果'a'和'b'的同一位都是1,则执行'...'。

表达式

c |= b

如果'b'中的某些位是1,那么将这些位在'c'中设为1。

该循环将测试并设置位向下移动。

祝好运!


1

0x010x80故意以十六进制表示,以强调它们作为类型unsigned char的最低有效位和最高有效位的重要性。

然而,作者犯了几个错误:

  • CHAR_BITS拼写错误:应该是CHAR_BIT
  • 使用CHAR_BIT而不是硬编码几乎通用的值8是为了完全可移植性的有价值的努力,但这种努力被使用0x80所抵消,如果CHAR_BIT == 8才有效。
  • 还有另一个微妙的可移植性问题:0x01 << shift在一个平台上会对shift = CHAR_BIT-1产生未定义的行为,其中sizeof(unsigned char) == sizeof(int),因为0x01的类型是int(而不是unsigned int,这是不符合直觉的吧?)。

以下是可以在所有符合规范的平台上运行的已更正版本:

#include <limits.h>

unsigned char reverse(unsigned char c) {
    int shift;
    unsigned char result = 0;

    for (shift = 0; shift < CHAR_BIT; shift++) {
        result <<= 1;
        result |= c & 1;
        c >>= 1;
    }
    return result;
}

0

0x01 表示 1,即个位上的数字 1;0x80 表示 128,即十六位上的数字 8。这些数字分别指代了八位数字中最低位和最高位。将它们进行移位操作可以得到字节中各个位的掩码。

编辑: 在十六进制数中,数字是按照 16 的幂次来排列的,而不是按照 10 的幂次。因此,从右边开始数第一个数字是个位(0x1 = 1),第二个数字是十六位(0x10 = 16),第三个数字是两百五十六位(0x100 = 256),以此类推。


十六进制位?你想修复它还是解释它? - Jonathan Leffler
2
如果你把每个nybble看作数字在该数的16进制表示中的位数,那么8就在十六位上。但我怀疑这不会解除OP的困惑。 - President James K. Polk

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接