我遇到了一个棘手的位操作问题。
据我所知,保存值的最小可变大小是8位的一个字节。 C / C ++中可用的位操作适用于整个字节单元。
想象一下,我有一张地图用信号10000(5位)替换二进制模式100100(6位)。如果来自文件的输入数据的第一个字节是10010001(8位)存储在char变量中,则它的一部分与6位模式匹配,因此被5位信号替换为1000001(7位)的结果。
我可以使用一个掩码来操作一个字节内的位,以便将最左边的位的结果变为10000(5位),但最右边的3位变得非常难以操作。我无法移动原始数据的最右边3位以获得正确的结果1000001(7位),然后在该char变量中填充1个填充位,该位变量应由下一个输入字节的第1位填充。
我想知道C / C ++是否可以实际上替换长度不适合Char(1字节)变量或甚至Int(4字节)的位模式。 C / C ++可以做到这一点,还是我们必须选择处理单比特操作的其他汇编语言?
我听说Power Basic可以比C / C ++更好地进行逐位操作。
答案 0 :(得分:1)
<<
shiftleft ^
XOR >>
向右移动~
一个补充使用这些操作,您可以轻松地隔离您感兴趣的部分并将它们作为整数进行比较。
说出字节001000100
,您想检查它是否包含1000
:
char k = (char)68;
char c = (char)8;
int i = 0;
while(i<5){
if((k<<i)>>(8-3-i) == c){
//do stuff
break;
}
}
这是非常粗略的代码,只是为了演示。
答案 1 :(得分:1)
如果时间和空间不重要,那么您可以将位转换为字符串表示并执行字符串替换,然后在需要时转换回来。 不是一个优雅的解决方案,但它有效。
答案 2 :(得分:1)
我想知道C / C ++是否能真正做到这一点 一种替代的比特模式 长度不适合Char(1 byte)变量或甚至Int(4字节)。
std :: bitset怎么样?
答案 3 :(得分:1)
这是一个可以满足您需求的小型读者课程。当然,您可能想为您的用例创建一个位编写器。
#include <iostream>
#include <sstream>
#include <cassert>
class BitReader {
public:
typedef unsigned char BitBuffer;
BitReader(std::istream &input) :
input(input), bufferedBits(8) {
}
BitBuffer peekBits(int numBits) {
assert(numBits <= 8);
assert(numBits > 0);
skipBits(0); // Make sure we have a non-empty buffer
return (((input.peek() << 8) | buffer) >> bufferedBits) & ((1 << numBits) - 1);
}
void skipBits(int numBits) {
assert(numBits >= 0);
numBits += bufferedBits;
while (numBits > 8) {
buffer = input.get();
numBits -= 8;
}
bufferedBits = numBits;
}
BitBuffer readBits(int numBits) {
assert(numBits <= 8);
assert(numBits > 0);
BitBuffer ret = peekBits(numBits);
skipBits(numBits);
return ret;
}
bool eof() const {
return input.eof();
}
private:
std::istream &input;
BitBuffer buffer;
int bufferedBits; // How many bits are buffered into 'buffer' (0 = empty)
};
答案 4 :(得分:0)
如果您可以一次性将数据读入矢量,请使用vector<bool>
。但是,查找和替换位序列可能更困难。
答案 5 :(得分:0)
如果我理解你的问题,你有一个输入流和输出流,你想要在输出中用输入5替换输入的6位 - 你的输出仍然应该是一个位流?
因此,最重要的程序员规则可以适用:Divide et impera! 您应该将组件分为三个部分:
输入流转换器:将输入流中的每个模式转换为char数组(环)缓冲区。如果我理解你的输入“命令”是8位长,那么没有什么特别的。
在环形缓冲区上进行替换,以每个匹配的6位模式替换为5位,但是用前导零“填充”5位,因此总长度仍为8位。
编写一个输出处理程序,它从环形缓冲区读取并让此输出处理程序只将7 LSB写入每个输入字节的输出流。当然,为此需要一些位操作。 如果您的环形缓冲区大小可以除以8和7(=是56的倍数),则最后会有一个干净的缓冲区,并且可以从1再次开始。
实现此目的最简单的方法是,只要输入数据可用,就迭代这3个步骤。
如果性能真的很重要并且您在多核CPU上运行,您甚至可以拆分步骤和3个线程,但是您必须小心地同步对环形缓冲区的访问。
答案 6 :(得分:0)
我认为以下是您想要的。
PATTERN_LEN = 6
PATTERNMASK = 0x3F //6 bits
PATTERN = 0x24 //b100100
REPLACE_LEN = 5
REPLACEMENT = 0x10 //b10000
void compress(uint8* inbits, uint8* outbits, int len)
{
uint16 accumulator=0;
int nbits=0;
uint8 candidate;
while (len--) //for all input bytes
{
//for each bit (msb first)
for (i=7;i<=0;i--)
{
//add 1 bit to accumulator
accumulator<<=1;
accumulator|=(*inbits&(1<<i));
nbits++;
//check for pattern
candidate = accumulator&PATTERNMASK;
if (candidate==PATTERN)
{
//remove pattern
accumulator>>=PATTERN_LEN;
//add replacement
accumulator<<=REPLACE_LEN;
accumulator|=REPLACMENT;
nbits+= (REPLACE_LEN - PATTERN_LEN);
}
}
inbits++;
//move accumulator to output to prevent overflow
while (nbits>8)
{
//copy the highest 8 bits
nbits-=8;
*outbits++ = (accumulator>>nbits)&0xFF;
//clear them from accumulator
accumulator&= ~(0xFF<<nbits);
}
}
//copy remainder of accumulator to output
while (nbits>0)
{
nbits-=8;
*outbits++ = (accumulator>>nbits)&0xFF;
accumulator&= ~(0xFF<<nbits);
}
}
您可以在中间使用开关或循环来检查候选人是否存在多种模式。在进行替换后可能需要进行一些特殊处理,以确保不会重新检查替换模式的匹配。
答案 7 :(得分:0)
#include <iostream>
#include <cstring>
size_t matchCount(const char* str, size_t size, char pat, size_t bsize) noexcept
{
if (bsize > 8) {
return 0;
}
size_t bcount = 0; // curr bit number
size_t pcount = 0; // curr bit in pattern char
size_t totalm = 0; // total number of patterns matched
const size_t limit = size*8;
while (bcount < limit)
{
auto offset = bcount%8;
char c = str[bcount/8];
c >>= offset;
char tpat = pat >> pcount;
if ((c & 1) == (tpat & 1))
{
++pcount;
if (pcount == bsize)
{
++totalm;
pcount = 0;
}
}
else // mismatch
{
bcount -= pcount; // backtrack
//reset
pcount = 0;
}
++bcount;
}
return totalm;
}
int main(int argc, char** argv)
{
const char* str = "abcdefghiibcdiixyz";
char pat = 'i';
std::cout << "Num matches = " << matchCount(str, 18, pat, 7) << std::endl;
return 0;
}