例如,如何读取从第二位开始的3比特整数值,或者写入从第五位开始的4比特整数值?
在我提出这个问题的两年后,我想以当时我还是一个完全新手时我希望解释的方式来解释它,这将对想要理解该过程的人最有益。
首先,忘记"11111111"的示例值,它并不适合用于过程的视觉说明。因此,让初始值为10111011
(187十进制),这将更能说明过程。
1-如何从第二位开始读取3位值:
___ <- those 3 bits
10111011
该值为101,或十进制下的5,有两种可能的获得方式:
在这种方法中,首先使用值00001110
(十进制14)对所需的位进行掩码处理,然后将其移位到指定位置:
___
10111011 AND
00001110 =
00001010 >> 1 =
___
00000101
表达式为:(value & 14) >> 1
这种方法类似,但操作顺序相反,意味着原始值会先进行移位,然后使用00000111
(7)进行掩码操作,只保留最后3位:
___
10111011 >> 1
___
01011101 AND
00000111
00000101
表达式为:(value >> 1) & 7
这两种方法的复杂度相同,因此性能不会有所不同。
2 - 如何从第二位开始编写3位值:
在这种情况下,初始值已知,如果代码中也是如此,您可能可以想出一种方法将已知值设置为使用更少操作的另一个已知值,但实际情况很少这样,大多数时候代码既不知道初始值,也不知道要写入的值。
这意味着为了成功地将新值“拼接”到字节中,目标位必须设置为零,然后将移位后的值“拼接”到位,这是第一步:
___
10111011 AND
11110001 (241) =
10110001 (masked original value)
第二步是将我们想要写入的值向左移动3位,假设我们想将其从101(5)更改为110(6)。 ___
00000110 << 1 =
___
00001100 (shifted "splice" value)
第三步是将掩码原始值与移位后的“拼接”值拼接起来。10110001 OR
00001100 =
___
10111101
整个过程的表达式为:(value & 241) | (6 << 1)
奖励 - 如何生成读写掩码:((1 << fieldLength) - 1) << (fieldIndex - 1)
,假设第一位的索引为1(而不是零)
- “位移和掩码”的读取掩码:(1 << fieldLength) - 1
(索引在这里不起作用,因为它总是被移位到第一位)
- 写入掩码:只需对“掩码与位移”掩码表达式使用~
运算符进行反转。00000001 << 3
00001000 - 1
00000111 << 1
00001110 ~ (read mask)
11110001 (write mask)
同样的例子适用于更宽的整数和任意位数和字段位置,移位和掩码值相应地变化。
还要注意,这些例子假设使用无符号整数,这是您想要使用整数作为可移植位域替代方案(常规位域在标准中无法保证可移植性)所需的。左右移运算都会插入填充的0,但对带符号整数进行右移运算时不是这种情况。
更容易的方法:
使用这组宏(但仅限于C++,因为它依赖于成员函数的生成):
#define GETMASK(index, size) ((((size_t)1 << (size)) - 1) << (index))
#define READFROM(data, index, size) (((data) & GETMASK((index), (size))) >> (index))
#define WRITETO(data, index, size, value) ((data) = (((data) & (~GETMASK((index), (size)))) | (((value) << (index)) & (GETMASK((index), (size))))))
#define FIELD(data, name, index, size) \
inline decltype(data) name() const { return READFROM(data, index, size); } \
inline void set_##name(decltype(data) value) { WRITETO(data, index, size, value); }
你可以选择最简单的方式:
struct A {
uint bitData;
FIELD(bitData, one, 0, 1)
FIELD(bitData, two, 1, 2)
};
并将位字段实现为属性,您可以轻松访问:
A a;
a.set_two(3);
cout << a.two();
在C++11之前,使用gcc的typeof
代替decltype
。
typedef struct A A;
来定义a
才能正常工作。此外,在C语言中,您不能在结构的范围内定义函数,这意味着需要进行一些重大更改(需要将结构传递给函数等——符号变化是非常重要的)。 - Jonathan Lefflerthis
指针(最好是为了C++编译器兼容性而使用self
)。 - dtechvalue
?它是字符数组吗?谢谢! - tommy.carstensen你需要进行移位和掩码操作,例如...
如果您想读取前两位,您只需要如下进行掩码操作:
int value = input & 0x3;
如果你想要进行偏移,你需要将其向右移动N位,然后屏蔽掉你想要的位:
int value = (intput >> 1) & 0x3;
根据您在问题中的要求,读取三个位。
int value = (input >> 1) & 0x7;
只需使用此方法,无需担心:
#define BitVal(data,y) ( (data>>y) & 1) /** Return Data.Y value **/
#define SetBit(data,y) data |= (1 << y) /** Set Data.Y to 1 **/
#define ClearBit(data,y) data &= ~(1 << y) /** Clear Data.Y to 0 **/
#define TogleBit(data,y) (data ^=BitVal(y)) /** Togle Data.Y value **/
#define Togle(data) (data =~data ) /** Togle Data value **/
uint8_t number = 0x05; //0b00000101
uint8_t bit_2 = BitVal(number,2); // bit_2 = 1
uint8_t bit_1 = BitVal(number,1); // bit_1 = 0
SetBit(number,1); // number = 0x07 => 0b00000111
ClearBit(number,2); // number =0x03 => 0b0000011
x = b >> p;
mask = (1 << n) - 1;
y = x & mask;
您可以将所有内容放在宏中:
#define TAKE_N_BITS_FROM(b, p, n) ((b) >> (p)) & ((1 << (n)) - 1)
例如,我如何读取从第二位开始的3位整数值?
int number = // whatever;
uint8_t val; // uint8_t is the smallest data type capable of holding 3 bits
val = (number & (1 << 2 | 1 << 3 | 1 << 4)) >> 2;
我假设"second bit"是指第二个比特,也就是实际上的第三个比特。
0x7
更容易,因为它与0b111
相同,这与(1 << 2 | 1 << 3 | 1 << 4)
相同。此外,您将其移位到第3位,而不是第2位。 - Geoffrey(number >> 2) & 0b111
。 - Geoffrey使用std::bitset读取字节
const int bits_in_byte = 8;
char myChar = 's';
cout << bitset<sizeof(myChar) * bits_in_byte>(myChar);
要进行编程,你需要使用位运算符,例如 & ^ | & << >>。请确保了解它们的作用。
例如,要得到 00100100,你需要将第一个比特设置为 1,并使用 << >> 运算符移动 5 次。如果你想继续编写,只需继续设置第一个比特并移动它。这非常像一台旧式打字机:你写入内容,然后移动纸张。
对于 00100100:将第一个比特设置为 1,移动 5 次,然后再将第一个比特设置为 1 并移动 2 次:
const int bits_in_byte = 8;
char myChar = 0;
myChar = myChar | (0x1 << 5 | 0x1 << 2);
cout << bitset<sizeof(myChar) * bits_in_byte>(myChar);
struct bitfield{
unsigned int bit : 1
}
struct bitfield *bitstream;
然后稍后像这样加载它(将char替换为int或任何你要加载的数据):
long int i;
int j, k;
unsigned char c, d;
bitstream=malloc(sizeof(struct bitfield)*charstreamlength*sizeof(char));
for (i=0; i<charstreamlength; i++){
c=charstream[i];
for(j=0; j < sizeof(char)*8; j++){
d=c;
d=d>>(sizeof(char)*8-j-1);
d=d<<(sizeof(char)*8-1);
k=d;
if(k==0){
bitstream[sizeof(char)*8*i + j].bit=0;
}else{
bitstream[sizeof(char)*8*i + j].bit=1;
}
}
}
bitstream[bitpointer].bit=...
或者
...=bitstream[bitpointer].bit
int x = 0xFF; //your number - 11111111
int y = x & ( 0x7 << 2 ) // 0x7 is 111
// and you shift it 2 to the left