C 解释这个功能

C 解释这个功能,c,comparison,bit-manipulation,bitwise-operators,C,Comparison,Bit Manipulation,Bitwise Operators,有人能给我解释一下为什么有人想使用位比较吗? 例如: 这就是我真正想知道的:“为什么要检查公共设置位?” x是任意正数。例如,如果您有许多状态标志,为了节省空间,您可能希望将每个标志作为一个位 因此,如果声明为字节,x将有8个标志。您给出的示例有点奇怪,但我将在嵌入式代码中始终使用位比较 我通常会有如下代码: volatile uint32_t *flags = 0x000A000; bool flagA = *flags & 0x1; bool flagB = *flags &

有人能给我解释一下为什么有人想使用位比较吗? 例如:

这就是我真正想知道的:“为什么要检查公共设置位?”


x是任意正数。

例如,如果您有许多状态标志,为了节省空间,您可能希望将每个标志作为一个位


因此,如果声明为字节,x将有8个标志。

您给出的示例有点奇怪,但我将在嵌入式代码中始终使用位比较

我通常会有如下代码:

volatile uint32_t *flags = 0x000A000;
bool flagA = *flags & 0x1;
bool flagB = *flags & 0x2;
bool flagC = *flags & 0x4;

您的特定示例测试二进制表示中的两个连续位是否为
1

我认为您指的是按位组合(在您的示例中是按位AND操作)。在字节、字或dword值作为位集合处理的情况下,这是一种非常常见的操作,例如状态信息,例如在SCADA或控制程序中。

这不是按位比较。它不返回布尔值

按位运算符用于读取和修改数字的各个位

n &   0x8   // Peek at bit3
n |=  0x8   // Set bit3
n &= ~0x8   // Clear bit3
n ^=  0x8   // Toggle bit3
使用位是为了节省空间。8个字符比一个字符中的8位占用更多的内存

以下示例使用给定的子网IP地址和子网的子网掩码获取IP子网的范围

uint32_t mask = (((255 << 8) | 255) << 8) | 255) << 8) | 255;
uint32_t ip   = (((192 << 8) | 168) << 8) |   3) << 8) |   4;

uint32_t first = ip & mask;
uint32_t last  = ip | ~mask;
uint32\u t mask=((255Ur示例是“测试一个数字是偶数还是奇数”:


更复杂的用途包括位掩码(单个整数中有多个布尔值,每个值占用一位空间)和加密/哈希(通常涉及位移位、异或等)

使用逐位操作有三个原因:

  • 您可以使用尽可能少的空间来存储信息
  • 您可以在单个CPU指令中比较/修改整个寄存器(例如,32、64或128位,具体取决于您的处理器),通常只需一个时钟周期。这意味着您可以以比常规算术更快的速度完成大量工作(某些类型)
  • 这很酷,有趣,程序员喜欢这些东西,当技术之间在效率/性能方面没有差异时,它们通常可以成为区别
您可以将其用于各种非常方便的事情。例如,在我的数据库中,我可以在一个很小的空间中存储关于我的客户的大量真/假信息(一个字节可以存储8个不同的真/假事实),然后使用“&”操作查询他们的状态:

  • 我的顾客是男性,单身,还是吸烟者

    if(customerFlags&(maleFlag | singleFlag | smokerFlag)==

    (maleFlag | singleFlag | smokerFlag))

  • 我的客户(任何组合)是男性、单身还是吸烟者

    if(customerFlags&(maleFlag | singleFlag | smokerFlag)!=0)

  • 我的客户不是男性,不是单身,不是吸烟者吗

    if(customerFlags&(maleFlag | singleFlag | smokerFlag)==0)

除了“检查公共位”,您还可以执行以下操作:

  • 某些算法,例如
    value&15
    相当于
    value%16
    ,速度要快得多。这只适用于某些数字,但如果您可以使用它,它将是一个非常好的优化

  • 数据打包/解包。例如,颜色通常表示为包含Alpha、红色、绿色和蓝色字节值的32位整数。红色值可以使用类似于
    Red=(value>>16)&255;
    的表达式进行提取(将值向下移动16位,然后切掉底部字节)

    • 数据操作和滑动。通过按位操作可以实现一些巧妙的技巧。例如,交换两个整数值而不需要使用第三个临时变量,或者将ARGB颜色值转换为另一种格式(例如RGBA或BGRA)

您的示例测试x是否设置了最多1位。
f
如果x是2的幂,则返回0;如果x不是,则返回非零。

比较结果在哪里?您可以解释一些示例吗?没有太多需要解释的内容;它检查位0、1和2(分别标记a、B和C)是否为“开”(高)例如,可能是从跳线读取。不,它测试
x
x*3
是否有任何公共设置位,这是完全不同的thing@JohnRiselvato,也许每一位代表一个来自机器外部的信号,你要检查附近的两个信号是否为一个。也许这表明某个设备有故障。这取决于t
x
是。@John Riselvato,可能您正在尝试执行某种压缩,两个相邻的集合位表示有压缩的机会。这实际上取决于什么是
x
。@John Riselvato只是(flag1&&flag2)|(flag2&&flag3)|(flag3&&flag4)的精简版本等等。@John Riselvato,一个数字不仅仅是一个数字。一个数字代表一些东西。
x
不是一个数字,
x
是一个数字。公平地说,C中没有任何东西返回布尔值。@Oli Charlesworth,你声称比较运算符不返回布尔值的说法是荒谬的。它们返回的要么是真值,要么是布尔值假值。算术运算符和位运算符不是这种情况。它们有许多不同的可能值,因此它们不是布尔值(只有两个可能值)。@ikegami:在C中,布尔运算返回的是
int
,而不是
布尔值“某些算术运算,例如,值&15相当于值%16快得多。”,我认为这些运算在现代PC上会花费相同的时间。这是不正确的吗?除法(和模)仍然比位运算花费更多的周期。然而,现代编译器通常足够聪明,可以在可能的情况下更改运算符(这实际上并不像你想象的那么频繁——例如,
n%2
n&1
如果
n
是否定的,则给出不同的答案。)
uint32_t mask = (((255 << 8) | 255) << 8) | 255) << 8) | 255;
uint32_t ip   = (((192 << 8) | 168) << 8) |   3) << 8) |   4;

uint32_t first = ip & mask;
uint32_t last  = ip | ~mask;
unsigned int number = ...;
bool isOdd = (0 != (number & 1));