如何设置、清除和切换一点?
当前回答
Visual C 2010,也许还有许多其他编译器,都直接支持内置的布尔运算。一个位有两个可能的值,就像一个布尔值一样,所以我们可以使用布尔值,即使在这种表示中,布尔值占用的内存空间比一个位多。这是有效的,即使sizeof()运算符也能正常工作。
bool IsGph[256], IsNotGph[256];
// Initialize boolean array to detect printable characters
for(i=0; i<sizeof(IsGph); i++) {
IsGph[i] = isgraph((unsigned char)i);
}
因此,对于您的问题,IsGph[i]=1或IsGph[i]=0使得设置和清除布尔值变得容易。
要查找不可打印的字符:
// Initialize boolean array to detect UN-printable characters,
// then call function to toggle required bits true, while initializing a 2nd
// boolean array as the complement of the 1st.
for(i=0; i<sizeof(IsGph); i++) {
if(IsGph[i]) {
IsNotGph[i] = 0;
} else {
IsNotGph[i] = 1;
}
}
注意,这段代码没有什么“特殊”之处。它有点像一个整数-从技术上讲,它是一个1位整数,可以容纳2个值,并且只能容纳2个。
我曾经使用这种方法查找重复的贷款记录,其中loan_number是ISAM密钥,使用6位贷款编号作为位数组的索引。8个月后,我们以惊人的速度证明了我们从中获取数据的主机系统实际上发生了故障。比特阵列的简单性使人们对其正确性的信心非常高——例如,与搜索方法相比。
其他回答
此程序用于将任何数据位从0更改为1或从1更改为0:
{
unsigned int data = 0x000000F0;
int bitpos = 4;
int bitvalue = 1;
unsigned int bit = data;
bit = (bit>>bitpos)&0x00000001;
int invbitvalue = 0x00000001&(~bitvalue);
printf("%x\n",bit);
if (bitvalue == 0)
{
if (bit == 0)
printf("%x\n", data);
else
{
data = (data^(invbitvalue<<bitpos));
printf("%x\n", data);
}
}
else
{
if (bit == 1)
printf("elseif %x\n", data);
else
{
data = (data|(bitvalue<<bitpos));
printf("else %x\n", data);
}
}
}
有时值得使用枚举来命名位:
enum ThingFlags = {
ThingMask = 0x0000,
ThingFlag0 = 1 << 0,
ThingFlag1 = 1 << 1,
ThingError = 1 << 8,
}
然后稍后使用这些名称,即写
thingstate |= ThingFlag1;
thingstate &= ~ThingFlag0;
if (thing & ThingError) {...}
设置、清除和测试。通过这种方式,您可以对代码的其余部分隐藏神奇的数字。
除此之外,我支持佩奇·鲁滕的解决方案。
比特场方法在嵌入式领域还有其他优势。您可以定义直接映射到特定硬件寄存器中的位的结构。
struct HwRegister {
unsigned int errorFlag:1; // one-bit flag field
unsigned int Mode:3; // three-bit mode field
unsigned int StatusCode:4; // four-bit status code
};
struct HwRegister CR3342_AReg;
您需要注意位打包顺序-我认为它首先是MSB,但这可能取决于实现。此外,验证编译器处理程序字段如何跨越字节边界。
然后,您可以像以前一样读取、写入和测试各个值。
尝试使用C语言中的以下函数之一更改n位:
char bitfield;
// Start at 0th position
void chang_n_bit(int n, int value)
{
bitfield = (bitfield | (1 << n)) & (~( (1 << n) ^ (value << n) ));
}
Or
void chang_n_bit(int n, int value)
{
bitfield = (bitfield | (1 << n)) & ((value << n) | ((~0) ^ (1 << n)));
}
Or
void chang_n_bit(int n, int value)
{
if(value)
bitfield |= 1 << n;
else
bitfield &= ~0 ^ (1 << n);
}
char get_n_bit(int n)
{
return (bitfield & (1 << n)) ? 1 : 0;
}
设置一位
使用按位OR运算符(|)设置位。
number |= 1UL << n;
这将设置数字的第n位。如果要将第1位设置为n-1,那么n应该为零,如果要设置第n位。
如果数字大于无符号长,则使用1ULL;1UL<<n的提升直到评估1UL<<n之后才发生,其中移动超过长的宽度是未定义的行为。这同样适用于所有其他示例。
清除一点
使用位AND运算符(&)清除位。
number &= ~(1UL << n);
这将清除数字的第n位。必须使用按位NOT运算符(~)反转位字符串,然后对其进行AND运算。
稍微扭动一下
XOR运算符(^)可用于切换位。
number ^= 1UL << n;
这将切换数字的第n位。
检查一点
你没有要求这样做,但我不妨补充一下。
要检查一位,请向右移动数字n,然后按位“与”:
bit = (number >> n) & 1U;
这将把数字第n位的值放入变量位。
将第n位更改为x
在2的补码C++实现中,可以通过以下方式将第n位设置为1或0:
number ^= (-x ^ number) & (1UL << n);
如果x为1,则设置位n,如果x为0,则清除位n。如果x有其他值,则会得到垃圾。x=!!x将其布尔化为0或1。
要使其独立于2的补码否定行为(其中-1设置了所有位,与1的补码或符号/大小C++实现不同),请使用无符号否定。
number ^= (-(unsigned long)x ^ number) & (1UL << n);
or
unsigned long newbit = !!x; // Also booleanize to force 0 or 1
number ^= (-newbit ^ number) & (1UL << n);
使用无符号类型进行可移植位操作通常是一个好主意。
or
number = (number & ~(1UL << n)) | (x << n);
(number&~(1UL<<n))将清除第n位,(x<<n)将第n位设置为x。
一般来说,不复制/粘贴代码也是一个好主意,因为很多人使用预处理器宏(如社区wiki答案)或某种封装。