位操作是直接对二进制位进行操作的技术,在Linux系统开发中尤为重要,特别是在以下场景: - 设备驱动开发 - 嵌入式系统编程 - 性能敏感型应用 - 内存受限环境
运算符 | 描述 | 示例 |
---|---|---|
& |
按位与 | a & b |
| |
按位或 | a | b |
^ |
按位异或 | a ^ b |
~ |
按位取反 | ~a |
<< |
左移 | a << n |
>> |
右移 | a >> n |
struct {
unsigned int is_keyboard : 1; // 1位
unsigned int is_mouse : 1; // 1位
unsigned int device_id : 6; // 6位
unsigned int reserved : 24; // 24位
} input_device;
Linux内核中的典型应用:在struct task_struct
等核心数据结构中广泛使用。
Linux内核提供了一组原子位操作API:
void set_bit(int nr, volatile unsigned long *addr);
void clear_bit(int nr, volatile unsigned long *addr);
void change_bit(int nr, volatile unsigned long *addr);
int test_and_set_bit(int nr, volatile unsigned long *addr);
这些操作在多核环境下保证原子性,常用于同步机制。
Linux内核中的位图实现:
#define BIT(nr) (1UL << (nr))
#define BIT_MASK(nr) (1UL << ((nr) % BITS_PER_LONG))
#define BIT_WORD(nr) ((nr) / BITS_PER_LONG)
应用场景: - 内存管理中的页分配 - 进程调度中的CPU亲和性设置 - 设备资源管理
static inline int ffs(int x)
{
int r = 1;
if (!x)
return 0;
if (!(x & 0xffff)) {
x >>= 16;
r += 16;
}
if (!(x & 0xff)) {
x >>= 8;
r += 8;
}
// ... 类似处理剩余位
return r;
}
Linux内核提供了ffs()
, fls()
等函数用于快速查找设置位。
#define __set_bit(nr, addr) \
(void)(((__typeof__(*(addr)) *)addr)[BIT_WORD(nr)] |= BIT_MASK(nr))
这种实现考虑了缓存行对齐,减少缓存失效。
// 设置寄存器的第3位
#define REG_ADDR 0x1234
*(volatile uint32_t *)REG_ADDR |= (1 << 3);
// 清除寄存器的第5位
*(volatile uint32_t *)REG_ADDR &= ~(1 << 5);
// 切换寄存器的第7位
*(volatile uint32_t *)REG_ADDR ^= (1 << 7);
#define READ_PERM (1 << 0)
#define WRITE_PERM (1 << 1)
#define EXEC_PERM (1 << 2)
#define ADMIN_PERM (1 << 3)
int has_permission(int user_perm, int required) {
return (user_perm & required) == required;
}
// 使用示例
int user = READ_PERM | WRITE_PERM;
if (has_permission(user, WRITE_PERM)) {
// 允许写操作
}
符号位问题:右移有符号数时,结果取决于实现
int x = -8;
x >>= 1; // 结果可能是-4(算术右移)或大正数(逻辑右移)
移位溢出:1 << 32
在32位系统上是未定义行为
# 以二进制格式显示变量
p /t variable
# 检查特定位
p (variable & (1 << bit_position)) != 0
Linux内核提供了一系列有用的位操作宏:
#define BIT(nr) (1UL << (nr))
#define BIT_ULL(nr) (1ULL << (nr))
#define GENMASK(h, l) (((~0UL) << (l)) & (~0UL >> (BITS_PER_LONG - 1 - (h))))
#define FIELD_PREP(mask, val) (((val) << (ffs(mask) - 1)) & (mask))
#define FIELD_GET(mask, reg) (((reg) & (mask)) >> (ffs(mask) - 1))
这些宏在设备驱动开发中特别有用。
位操作是Linux系统编程中的核心技能,合理使用可以显著提升程序性能和资源利用率。掌握这些技术对于深入理解Linux内核和开发高效的系统软件至关重要。建议读者通过实际项目练习这些技术,并深入研究Linux内核源码中的位操作实现。