我猜不出如何解决以下问题。假设我有一个字符串或整数类型变量数组(uchar,char,integer,等等)。这些数据类型中的每一种都是1字节长或更长。
我想从这样的数组中读取但是读取小于1字节的片段,例如3位(值0-7)。我试着做一个像
这样的循环cout << ( (tab[index] >> lshift & lmask) | (tab[index+offset] >> rshift & rmask) );
但猜测如何设置这些变量是我无法实现的。解决这个问题的方法是什么?
很抱歉,如果有人问过问题,但搜索没有给出答案。
答案 0 :(得分:1)
我确信这不是最佳解决方案,因为代码中的一些效率低下可以消除,但我认为这个想法是可行的。我只是简单地测试了一下:
void bits(uint8_t * src, int arrayLength, int nBitCount) {
int idxByte = 0; // byte index
int idxBitsShift = 7; // bit index: start at the high bit
// walk through the array, computing bit sets
while (idxByte < arrayLength) {
// compute a single bit set
int nValue = 0;
for (int i=2; i>=0; i--) {
nValue += (src[idxByte] & (1<<idxBitsShift)) >> (idxBitsShift-i);
if ((--idxBitsShift) < 0) {
idxBitsShift=8;
if (++idxByte >= arrayLength)
break;
}
}
// print it
printf("%d ", nValue);
}
}
int main() {
uint8_t a[] = {0xFF, 0x80, 0x04};
bits(a, 3, 3);
}
跨越字节边界收集位的东西是PITA的一部分,所以我通过一次这样做,然后在nValue
中一起收集这些位来避免所有这些。您可以拥有更聪明的代码,一次执行这三个(或多个)位,但就我而言,对于这样的问题,通常最好从一个简单的解决方案开始(除非您已经知道如何做更好的一个)然后做一些更复杂的事情。
答案 1 :(得分:0)
简而言之,数据在内存中的排列方式严格依赖于:
现在,你不能用这个基本原理“反汇编”数据结构而不破坏它自己的含义,简单地说,如果你要在“位域”中细分你的变量,你只是想象一个未定义的值。
在计算机科学中,存在以块为单位构造的数据结构或信息,例如许多散列算法/散列结果,但是数值不是那样存储的,你应该知道你在做什么来防止任何数据丢失。 / p>
另外需要注意的是,你对“小于1个字节的片段”的定义没有多大意义,它也是高度侵入性的,你在这里丢失了抽象,你也可以做坏事。
答案 2 :(得分:0)
这是我设置变量的各个位的最佳方法: 假设我们需要将variable1的前四位(char或其他字节长变量)设置为1010
variable1 &= 0b00001111; //Zero the first four bytes
variable1 |= 0b10100000; //Set them to 1010, its important that any unaffected bits be zero
这可以扩展到所需的任何位,方法是将零置于与您希望设置的位相对应的第一个数字(示例中的前四个),并将零置于与您所在位相对应的第二个数字中希望在第二个数字中保持中立(示例中的最后四个)。第二个数字也可以通过将您想要的值按位移到适当的位数(在示例中为4)来推导出来。
在回应您的评论时,可以按照以下方式对其进行修改,以适应更大的可变性:
对于此操作,假设您希望能够修改非起始和非结束位,我们将需要两个移位。在这种情况下,有两组位是第一组(从左侧)未受影响的位和第二组。如果你想修改四个位从左边跳过第一位(1 这四个位 111用于单个字节),第一个移位将是7,第二个移位将是5。 / p>
variable1 &= ( ( 0b11111111 << shift1 ) | 0b11111111 >> shift2 );
接下来,我们希望分配的值需要移位和/或。
但是,我们需要第三次转换来考虑我们想要设置的位数。
这种转变(我们将其称为shift3
)是shift1
减去我们希望修改的位数(如前面提到的4)。
variable1 |= ( value << shift3 );