C语言中的位操作
在进行按位操作前,应当熟悉十六进制数和二进制数的简易转换

四位权值法(4位分组法)转换二进制到十六进制

步骤:

  1. 将二进制数按四位分组
    • 从右往左,每四位一组。如果二进制数的位数不满足四位的倍数,可以在最左边补充零。
  2. 计算每组四位二进制数的十六进制值
    • 每组四位二进制数对应的权值是 8, 4, 2, 1,分别对应从左到右的四个位。
    • 计算每一组的十进制值:
      十进制值 = (最左位 * 8) + (次左位 * 4) + (次右位 * 2) + (最右位 * 1)
  3. 将每组的十进制值转换为十六进制
    • 得到的十进制值直接对应十六进制数,如果十进制值大于等于10,使用字母A-F表示。
  4. 拼接每组的十六进制数
    • 最后将所有转换得到的十六进制数拼接起来,形成完整的十六进制表示。

例 1:二进制 101101 转换为十六进制

  1. 按四位分组
    • 10110110 1101
    • 补零:0010 1101
  2. 计算每组十六进制值
    • 第一组 0010
      • 0 * 8 + 0 * 4 + 1 * 2 + 0 * 1 = 2 → 十六进制为 2
    • 第二组 1101
      • 1 * 8 + 1 * 4 + 0 * 2 + 1 * 1 = 8 + 4 + 1 = 13 → 十六进制为 D
  3. 拼接结果
    • 十六进制结果为 0x2D

例 2:二进制 10101011 转换为十六进制

  1. 按四位分组
    • 101010111010 1011
  2. 计算每组十六进制值
    • 第一组 1010
      • 1 * 8 + 0 * 4 + 1 * 2 + 0 * 1 = 8 + 2 = 10 → 十六进制为 A
    • 第二组 1011
      • 1 * 8 + 0 * 4 + 1 * 2 + 1 * 1 = 8 + 2 + 1 = 11 → 十六进制为 B
  3. 拼接结果
    • 十六进制结果为 0xAB

在C语言中,移位操作(Shift Operations)指的是通过操作符将二进制数的位向左或向右移动。移位操作常用于高效的数值计算、位操作和硬件编程中。

1.移位操作符

  1. 左移操作符 (<<):将数值的二进制位向左移动指定的位数,左移时高位丢弃,低位补零。
    • 例如:a << n,表示将 a 的二进制位左移 n 位。
  2. 右移操作符 (>>):将数值的二进制位向右移动指定的位数,右移时,符号位(对于有符号数)通常会被扩展,高位补符号位(对于无符号数补零)。
    • 例如:a >> n,表示将 a 的二进制位右移 n 位。

例:以 0x123 为例

假设我们有一个十六进制数 0x123,其二进制表示为:

0x123 = 0001 0010 0011 (二进制)

左移操作:<<

  1. 左移 1 位
    0x123 << 1
    • 计算:二进制 0001 0010 0011 左移 1 位,结果是 0010 0100 0110
    • 十六进制表示:0x246
    • 解释:左移 1 位相当于将数字乘以 2。
    结果: 0x123 << 1 = 0x246
  2. 左移 2 位
    0x123 << 2
    • 计算:二进制 0001 0010 0011 左移 2 位,结果是 0100 1000 1100
    • 十六进制表示:0x48C
    • 解释:左移 2 位相当于将数字乘以 4。
    结果: 0x123 << 2 = 0x48C
  3. 左移 4 位
    0x123 << 4
    • 计算:二进制 0001 0010 0011 左移 4 位,结果是 0001 0010 0011 0000
    • 十六进制表示:0x1230
    • 解释:左移 4 位相当于将数字乘以 16。
    结果: 0x123 << 4 = 0x1230

右移操作:>>

  1. 右移 1 位
    0x123 >> 1
    • 计算:二进制 0001 0010 0011 右移 1 位,结果是 0000 1001 0001
    • 十六进制表示:0x91
    • 解释:右移 1 位相当于将数字除以 2。
    结果: 0x123 >> 1 = 0x91
  2. 右移 2 位
    0x123 >> 2
    • 计算:二进制 0001 0010 0011 右移 2 位,结果是 0000 0100 1000
    • 十六进制表示:0x48
    • 解释:右移 2 位相当于将数字除以 4。
    结果: 0x123 >> 2 = 0x48
  3. 右移 4 位
    0x123 >> 4
    • 计算:二进制 0001 0010 0011 右移 4 位,结果是 0001 0010。十六进制表示:0x12。解释:右移 4 位相当于将数字除以 16。
    结果: 0x123 >> 4 = 0x012

2. 取反操作(~

取反操作将二进制数的每一位反转,即 0 变成 1,1 变成 0。

例子:~0x123

  1. 原始值 0x123 对应的二进制是: 0x123 = 0001 0010 0011 (二进制)
  2. 取反~0x123 = 1110 1101 1100 (二进制)
  3. 计算结果
    • 取反后的二进制值是 1110 1101 1100
    • 这是 0xEDC 的十六进制表示。

所以,~0x123 的结果是 0xEDC

3. 位与操作(&

位与操作会逐位比较两个操作数的二进制位,只有当两个对应位都是 1 时,结果位才为 1,否则为 0。

例子:0x123 & 0xFF

原始值

0x123 的二进制是:0001 0010 0011

0xFF 的二进制是:1111 1111(即全 8 位 1)。

位与操作
0x123 & 0xFF = 0001 0010 0011
             & 0000 1111 1111
            -----------------------
             = 0000 0010 0011

计算结果

结果的二进制是 0010 0011,十六进制是 0x23

4. 位或操作(|

位或操作会逐位比较两个操作数的二进制位,只要两个对应位中有一个是 1,结果位就为 1。

例子:0x123 | 0xFF

原始值

0x123 的二进制是:0001 0010 0011

0xFF 的二进制是:1111 1111

位或操作: 
0x123 | 0xFF = 0001 0010 0011 
             | 0000 1111 1111 
           ----------------------- 
             = 0001 1111 1111

计算结果

结果的二进制是 1111 1111,十六进制是 0x1FF

置位(Set)和清位(Clear)是位操作中常见的操作,它们主要用来修改某一特定位置的值,通常用于控制寄存器或位域,或者在一些算法中进行标记。

5. 置位操作(Set)

置位操作的目的是将某一特定位置的位设置为 1,通常用于激活某个标志位或开启某个功能。

位(bit)是从第0位开始。

置位操作的常见方法:

  • 使用 按位或(| 操作符。

示例:

假设我们有一个变量 x 和一个掩码 mask,我们想要将 x 的第 n 位置为 1,可以使用如下操作:

x = x | (1 << n);
  • 1 << n:将 1 向左移动 n 位,生成一个只有第 n 位为 1 的掩码。
  • x | (1 << n):将 x 和这个掩码按位“或”运算,确保第 n 位为 1。

例子:

unsigned int x = 0x123;  // 二进制为 0001 0010 0011
x = x | (1 << 7);        // 置第 7 位为 1

1 << 7 会生成 1000 0000,与 x 进行位或操作:

  0001 0010 0011 (0x123) 
| 0000 1000 0000 
------------ 
  0001 1010 0011 (结果 0x1A3)

所以,置位操作后,x 的值变成了 0x1A3

6. 清位操作(Clear)

清位操作的目的是将某一特定位置的位设置为 0,通常用于关闭某个标志位或禁用某个功能。

清位操作的常见方法:

  • 使用 按位与(& 操作符,并将目标位置的掩码取反。
掩码(Mask)在计算机科学中,尤其是位操作中,指的是一个二进制数,用来操作另一个二进制数的特定位。掩码通常用于 选择修改 特定的位。通过与目标数进行按位与、按位或、按位异或等运算,掩码可以帮助我们从数值中提取特定位,或者设置、清除特定的位。

示例:

假设我们有一个变量 x 和一个掩码 mask,我们想要将 x 的第 n 位清零,可以使用如下操作:

x = x & ~(1 << n);
  • 1 << n:将 1 向左移动 n 位,生成一个只有第 n 位为 1 的掩码。
  • ~(1 << n):对该掩码取反,生成一个只有第 n 位为 0 其余为 1 的掩码。
  • x & ~(1 << n):将 x 和这个掩码按位“与”运算,确保第 n 位为 0。

例子:

unsigned int x = 0x123;  // 二进制为 0001 0010 0011
x = x & ~(1 << 7);       // 清第 7 位为 0

1 << 7 会生成 1000 0000,取反后得到 0111 1111

x & 0111 1111 结果是:

  0001 0010 0011 (0x123) 
& 1111 0111 1111 
   ------------ 
  0001 0010 0011 (结果 0x123)

此例中,虽然我们试图清除第 7 位,但 x 原本并没有在第 7 位设置为 1,因此操作结果没有变化。


总结

  • 左移 (<<) 会将数值乘以 2 的幂次方。
  • 右移 (>>) 会将数值除以 2 的幂次方(对于整数)。
  • 对于 无符号数,左移和右移不会出现符号位扩展问题,结果只是单纯的位移。
  • 对于 有符号数,右移时符号位会扩展,保持符号正确。
  • 取反(~:将二进制数的每一位反转,~0x123 结果为 0xEDC
  • 位与(&:只有对应位都为 1 时结果才为 1,0x123 & 0xFF 结果为 0x03
  • 位或(|:只要对应位有一个是 1 结果就是 1,0x123 | 0xFF 结果为 0xFF
  • 置位操作:通过按位或(|)将目标位设置为 1,常用于激活或开启某个功能。
  • 清位操作:通过按位与(&)并取反掩码将目标位设置为 0,常用于关闭或禁用某个功能。
上一篇
下一篇