如何设置、清除和切换一点?
当前回答
int set_nth_bit(int num, int n){
return (num | 1 << n);
}
int clear_nth_bit(int num, int n){
return (num & ~( 1 << n));
}
int toggle_nth_bit(int num, int n){
return num ^ (1 << n);
}
int check_nth_bit(int num, int n){
return num & (1 << n);
}
其他回答
有时值得使用枚举来命名位:
enum ThingFlags = {
ThingMask = 0x0000,
ThingFlag0 = 1 << 0,
ThingFlag1 = 1 << 1,
ThingError = 1 << 8,
}
然后稍后使用这些名称,即写
thingstate |= ThingFlag1;
thingstate &= ~ThingFlag0;
if (thing & ThingError) {...}
设置、清除和测试。通过这种方式,您可以对代码的其余部分隐藏神奇的数字。
除此之外,我支持佩奇·鲁滕的解决方案。
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个月后,我们以惊人的速度证明了我们从中获取数据的主机系统实际上发生了故障。比特阵列的简单性使人们对其正确性的信心非常高——例如,与搜索方法相比。
使用标准C++库:std::bitset<N>。
或者Boost版本:Boost::dynamic_bitset。
没有必要自己动手:
#include <bitset>
#include <iostream>
int main()
{
std::bitset<5> x;
x[1] = 1;
x[2] = 0;
// Note x[0-4] valid
std::cout << x << std::endl;
}
[Alpha:] > ./a.out
00010
与标准库编译时大小的位集相比,Boost版本允许运行时大小的比特集。
模板版本(放在头文件中),支持更改多位(适用于AVR微控制器btw):
namespace bit {
template <typename T1, typename T2>
constexpr inline T1 bitmask(T2 bit)
{return (T1)1 << bit;}
template <typename T1, typename T3, typename ...T2>
constexpr inline T1 bitmask(T3 bit, T2 ...bits)
{return ((T1)1 << bit) | bitmask<T1>(bits...);}
/** Set these bits (others retain their state) */
template <typename T1, typename ...T2>
constexpr inline void set (T1 &variable, T2 ...bits)
{variable |= bitmask<T1>(bits...);}
/** Set only these bits (others will be cleared) */
template <typename T1, typename ...T2>
constexpr inline void setOnly (T1 &variable, T2 ...bits)
{variable = bitmask<T1>(bits...);}
/** Clear these bits (others retain their state) */
template <typename T1, typename ...T2>
constexpr inline void clear (T1 &variable, T2 ...bits)
{variable &= ~bitmask<T1>(bits...);}
/** Flip these bits (others retain their state) */
template <typename T1, typename ...T2>
constexpr inline void flip (T1 &variable, T2 ...bits)
{variable ^= bitmask<T1>(bits...);}
/** Check if any of these bits are set */
template <typename T1, typename ...T2>
constexpr inline bool isAnySet(const T1 &variable, T2 ...bits)
{return variable & bitmask<T1>(bits...);}
/** Check if all these bits are set */
template <typename T1, typename ...T2>
constexpr inline bool isSet (const T1 &variable, T2 ...bits)
{return ((variable & bitmask<T1>(bits...)) == bitmask<T1>(bits...));}
/** Check if all these bits are not set */
template <typename T1, typename ...T2>
constexpr inline bool isNotSet (const T1 &variable, T2 ...bits)
{return ((variable & bitmask<T1>(bits...)) != bitmask<T1>(bits...));}
}
使用示例:
#include <iostream>
#include <bitset> // for console output of binary values
// and include the code above of course
using namespace std;
int main() {
uint8_t v = 0b1111'1100;
bit::set(v, 0);
cout << bitset<8>(v) << endl;
bit::clear(v, 0,1);
cout << bitset<8>(v) << endl;
bit::flip(v, 0,1);
cout << bitset<8>(v) << endl;
bit::clear(v, 0,1,2,3,4,5,6,7);
cout << bitset<8>(v) << endl;
bit::flip(v, 0,7);
cout << bitset<8>(v) << endl;
}
BTW:如果不向编译器发送优化器参数(例如:-O3),则不使用constexpr和inline。请随时尝试以下代码https://godbolt.org/并查看ASM输出。
更一般地,对于任意大小的位图:
#define BITS 8
#define BIT_SET( p, n) (p[(n)/BITS] |= (0x80>>((n)%BITS)))
#define BIT_CLEAR(p, n) (p[(n)/BITS] &= ~(0x80>>((n)%BITS)))
#define BIT_ISSET(p, n) (p[(n)/BITS] & (0x80>>((n)%BITS)))