按位运算符控制整数类型的单独位:
& — 按位与| — 按位或^ — 按位异或~ — 按位非<< — 左移>> — 右移特性:
int、unsigned int等)。>>)时,带符号数(signed)可能会导致算术或逻辑移位——这取决于编译器。unsigned类型,以避免符号扩展。示例:
unsigned int flags = 0; flags |= 0x1; // 设置第0位 flags &= ~0x2; // 清除第1位 if ((flags & 0x4) != 0) { /* ... */ } // 检查第2位
带符号整数(
signed int)和无符号整数(unsigned int)进行右移(>>)操作有什么区别?
常见的错误答案: 认为右移操作总是将零插入左边,不管符号如何。
正确答案:
对于unsigned int类型,右移(>>)总是插入零。对于signed int,要插入符号(如果数是负的则插入1)或零——这取决于编译器的实现(架构和C标准的规则)。
示例:
signed int a = -8; unsigned int b = (unsigned int)a; printf("%d\n", a >> 1); printf("%u\n", b >> 1);
在第一种情况下,结果依赖于编译器;在第二种情况下总是逻辑移位,并插入零。
故事
在协议处理代码中,信号标志存储在char类型中。程序员使用了8位移位(flag << 8),这由于溢出和类型提升规则导致数据丢失——结果总是为零。
故事
从网络协议中读取数据(大端模式)。使用按位操作来组合字节时,没有转换为unsigned,这有时导致在读取结构字段时出现意外的负值。
故事
使用~(按位非)来清除int类型值的位(例如,~0x80)被认为是0x7F,但实际上得到的结果是负数-129,这在后续计算和逻辑检查中导致错误。