(9)位运算

1. 位运算的概念

位运算操作的是整数在内存中的二进制位。C 语言提供了以下几种位运算操作符:

按位与(&)
  • 运算规则:将两个操作数对应的二进制位进行与运算。只有当两个对应位都为 1 时,结果位才为 1,否则为 0。
  • 示例代码
#include <stdio.h>

int main() {
    int num1 = 5;  // 二进制表示为 0101
    int num2 = 3;  // 二进制表示为 0011
    int result = num1 & num2;  // 0101 & 0011 = 0001
    printf("5 & 3 的结果: %d\n", result);
    return 0;
}
按位或(|)
  • 运算规则:将两个操作数对应的二进制位进行或运算。只要两个对应位中有一个为 1,结果位就为 1。
  • 示例代码
#include <stdio.h>

int main() {
    int num1 = 5;  // 二进制表示为 0101
    int num2 = 3;  // 二进制表示为 0011
    int result = num1 | num2;  // 0101 | 0011 = 0111
    printf("5 | 3 的结果: %d\n", result);
    return 0;
}
按位异或(^)
  • 运算规则:将两个操作数对应的二进制位进行异或运算。当两个对应位不同时,结果位为 1;相同时,结果位为 0。
  • 示例代码
#include <stdio.h>

int main() {
    int num1 = 5;  // 二进制表示为 0101
    int num2 = 3;  // 二进制表示为 0011
    int result = num1 ^ num2;  // 0101 ^ 0011 = 0110
    printf("5 ^ 3 的结果: %d\n", result);
    return 0;
}
取反(~)
  • 运算规则:对操作数的每一位进行取反操作,0 变为 1,1 变为 0。需要注意的是,取反操作符是单目运算符,它对一个操作数进行操作。
  • 示例代码
#include <stdio.h>

int main() {
    int num = 5;  // 二进制表示为 00000101
    int result = ~num;  // 取反后为 11111010(在有符号整数表示中,这是 -6 的补码形式)
    printf("~5 的结果: %d\n", result);
    return 0;
}
左移(<<)
  • 运算规则:将操作数的所有二进制位向左移动指定的位数,右边空出的位用 0 填充。左移一位相当于乘以 2。
  • 示例代码
#include <stdio.h>

int main() {
    int num = 5;  // 二进制表示为 00000101
    int result = num << 2;  // 左移 2 位后为 00010100,即 20
    printf("5 << 2 的结果: %d\n", result);
    return 0;
}
右移(>>)
  • 运算规则:将操作数的所有二进制位向右移动指定的位数。对于无符号数,左边空出的位用 0 填充;对于有符号数,如果是算术右移(大多数编译器的实现方式),左边空出的位用符号位填充。右移一位相当于除以 2(对于无符号数和正数)。
  • 示例代码
#include <stdio.h>

int main() {
    int num = 12;  // 二进制表示为 00001100
    int result = num >> 2;  // 右移 2 位后为 00000011,即 3
    printf("12 >> 2 的结果: %d\n", result);
    return 0;
}

2. 位段的概念

位段(bit - field)是一种特殊的结构体成员,它允许以位为单位指定结构体成员所占的存储空间大小。通过位段,可以更紧凑地存储数据,尤其是在处理一些硬件相关的数据或者需要节省内存空间的情况下。

以下是位段的示例:

#include <stdio.h>

// 定义一个包含位段的结构体
struct BitFieldExample {
    unsigned int field1 : 3;  // 位段 field1 占 3 位
    unsigned int field2 : 5;  // 位段 field2 占 5 位
    unsigned int field3 : 4;  // 位段 field3 占 4 位
};

int main() {
    struct BitFieldExample example;
    example.field1 = 3;  // 二进制为 011,存储在低 3 位
    example.field2 = 7;  // 二进制为 00111,存储在接下来的 5 位
    example.field3 = 9;  // 二进制为 1001,存储在再接下来的 4 位

    // 注意:位段的存储顺序和字节顺序(大端序或小端序)有关,这里假设为小端序
    // 结构体总共占 2 个字节(3 + 5 + 4 = 12 位,向上取整到字节)
    unsigned short int *ptr = (unsigned short int *)&example;
    printf("存储的值(十六进制): 0x%x\n", *ptr);

    return 0;
}

在这个示例中,struct BitFieldExample结构体中的成员field1field2field3都是位段。它们在内存中是紧凑存储的,总共占用不超过一个整数的空间(这里假设为 2 个字节,因为总共 12 位)。

3. 在程序中应用位运算

设置和清除特定的位
  • 设置某一位为 1(使用按位或)
    假设要将一个整数num的第n位(从右往左数,最低位为第 0 位)设置为 1。可以使用以下代码:
#include <stdio.h>

int main() {
    int num = 10;  // 二进制为 1010
    int n = 1;     // 设置第 1 位
    num = num | (1 << n);  // 将第 1 位设置为 1,结果为 1010 | 0010 = 1010
    printf("设置第 %d 位后的结果: %d\n", n, num);
    return 0;
}
  • 清除某一位为 0(使用按位与和取反)
    要将一个整数num的第n位清除为 0,可以使用以下代码:
#include <stdio.h>

int main() {
    int num = 10;  // 二进制为 1010
    int n = 2;     // 清除第 2 位
    num = num & ~(1 << n);  // 将第 2 位清除为 0,结果为 1010 & 1011 = 1000
    printf("清除第 %d 位后的结果: %d\n", n, num);
    return 0;
}
检查特定的位是否为 1(使用按位与)
#include <stdio.h>

int main() {
    int num = 10;  // 二进制为 1010
    int n = 1;     // 检查第 1 位
    if (num & (1 << n)) {
        printf("第 %d 位是 1\n", n);
    } else {
        printf("第 %d 位是 0\n", n);
    }
    return 0;
}
位运算在枚举中的应用(使用位掩码)

可以使用位运算来实现枚举类型中的多个标志位。例如:

#include <stdio.h>

// 定义枚举类型,每个枚举值对应一个位掩码
enum Options {
    OPTION_A = 1 << 0,  // 0001
    OPTION_B = 1 << 1,  // 0010
    OPTION_C = 1 << 2   // 0100
};

int main() {
    int options = OPTION_A | OPTION_C;  // 设置选项 A 和 C,二进制为 0101
    if (options & OPTION_A) {
        printf("选项 A 被选中\n");
    }
    if (options & OPTION_B) {
        printf("选项 B 被选中\n");
    }
    if (options & OPTION_C) {
        printf("选项 C 被选中\n");
    }
    return 0;
}

在这个示例中,通过位运算可以方便地组合和检查枚举类型中的多个选项。位运算在底层编程、硬件驱动开发、数据压缩、加密算法等领域都有广泛的应用。通过灵活运用位运算,可以提高程序的效率和优化内存使用。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值