在位流中设置位
Setting bits in a bit stream
我在处理遗留代码时遇到了以下 C 函数,我对代码的组织方式感到非常困惑。我可以看到该函数正在尝试在位流中的给定位置设置位,但我无法理解单个语句和表达式。有人能解释一下为什么开发人员在这里和那里使用除以 8 (/8) 和取模 8 (%8) 表达式吗?有没有一种简单的方法可以在 c 中读取这些类型的位操作函数?
static void setBits(U8 *input, U16 *bPos, U8 len, U8 val)
{
U16 pos;
if (bPos==0)
{
pos=0;
}
else
{
pos = *bPos;
*bPos += len;
}
input[pos/8] = (input[pos/8]&(0xFF-((0xFF>>(pos%8))&(0xFF<<(pos%8+len>=8?0:8-(pos+len)%8)))))
|((((0xFF>>(8-len)) & val)<<(8-len))>>(pos%8));
if ((pos/8 == (pos+len)/8)|(!((pos+len)%8)))
return;
input[(pos+len)/8] = (input[(pos+len)/8]
&(0xFF-(0xFF<<(8-(pos+len)%8))))
|((0xFF>>(8-len)) & val)<<(8-(pos+len)%8);
}
please explain why the developer used divison by 8 (/8) and modulus 8 (%8) expressions here and there
首先,请注意字节的各个位编号为 0 到 7,其中第 0 位是最低位。一个字节有 8 位,因此 "magic number" 8.
一般来说:如果您有任何原始数据,它由 n
字节组成,因此始终可以被视为字节数组 uint8_t data[n]
。要访问该字节数组中的位 x
,您可以这样做:
给定 x = 17
,然后在字节号 17/8 = 2
中找到位 x。请注意,整数除法 "floors" 得到的值不是 2.125,而是 2。
整数除法的余数给出了该字节中的位位置,17%8 = 1
。
所以位号 17 位于字节 2 的位 1。data[2]
给出了字节。
为了从 C 中的一个字节中屏蔽掉一个位,使用了按位与运算符 &
。为了使用它,需要一个位掩码。这样的位掩码最好通过将值 1 移动所需的位数来获得。位掩码可能最清楚地用十六进制表示,一个字节的可能位掩码将是 (1<<0) == 0x01
、 (1<<1) == 0x02
、(1<<3) == 0x04
、(1<<4) == 0x08
等等。
在这种情况下 (1<<1) == 0x02
。
C代码:
uint8_t data[n];
...
size_t byte_index = x / 8;
size_t bit_index = x % 8;
bool is_bit_set;
is_bit_set = ( data[byte_index] & (1<<bit_index) ) != 0;
我在处理遗留代码时遇到了以下 C 函数,我对代码的组织方式感到非常困惑。我可以看到该函数正在尝试在位流中的给定位置设置位,但我无法理解单个语句和表达式。有人能解释一下为什么开发人员在这里和那里使用除以 8 (/8) 和取模 8 (%8) 表达式吗?有没有一种简单的方法可以在 c 中读取这些类型的位操作函数?
static void setBits(U8 *input, U16 *bPos, U8 len, U8 val)
{
U16 pos;
if (bPos==0)
{
pos=0;
}
else
{
pos = *bPos;
*bPos += len;
}
input[pos/8] = (input[pos/8]&(0xFF-((0xFF>>(pos%8))&(0xFF<<(pos%8+len>=8?0:8-(pos+len)%8)))))
|((((0xFF>>(8-len)) & val)<<(8-len))>>(pos%8));
if ((pos/8 == (pos+len)/8)|(!((pos+len)%8)))
return;
input[(pos+len)/8] = (input[(pos+len)/8]
&(0xFF-(0xFF<<(8-(pos+len)%8))))
|((0xFF>>(8-len)) & val)<<(8-(pos+len)%8);
}
please explain why the developer used divison by 8 (/8) and modulus 8 (%8) expressions here and there
首先,请注意字节的各个位编号为 0 到 7,其中第 0 位是最低位。一个字节有 8 位,因此 "magic number" 8.
一般来说:如果您有任何原始数据,它由 n
字节组成,因此始终可以被视为字节数组 uint8_t data[n]
。要访问该字节数组中的位 x
,您可以这样做:
给定 x = 17
,然后在字节号 17/8 = 2
中找到位 x。请注意,整数除法 "floors" 得到的值不是 2.125,而是 2。
整数除法的余数给出了该字节中的位位置,17%8 = 1
。
所以位号 17 位于字节 2 的位 1。data[2]
给出了字节。
为了从 C 中的一个字节中屏蔽掉一个位,使用了按位与运算符 &
。为了使用它,需要一个位掩码。这样的位掩码最好通过将值 1 移动所需的位数来获得。位掩码可能最清楚地用十六进制表示,一个字节的可能位掩码将是 (1<<0) == 0x01
、 (1<<1) == 0x02
、(1<<3) == 0x04
、(1<<4) == 0x08
等等。
在这种情况下 (1<<1) == 0x02
。
C代码:
uint8_t data[n];
...
size_t byte_index = x / 8;
size_t bit_index = x % 8;
bool is_bit_set;
is_bit_set = ( data[byte_index] & (1<<bit_index) ) != 0;