问题描述
我有不同的位长度的65参数,我需要填写字节串。 Parametrs将连续字节串来填补。例如,假设第一个参数是1位长,所以它将在字节串的第一个字节的第0位的位置来填补。现在,第二个参数是假设9位长。因此,这parametr的前7位将在同一个八比特填充和接下来的2位应该前往下一个八位位组的第0和第1位的位置。同样其他参数将得到填补的字节串。我试着写在那里我传递的指向当前八位位组的位位置,并从那里数据将被复制源指针的函数。但我发现在逻辑上实现的难度。我曾试过无数的逻辑(位操作,位移,旋转等),但无法获得正确的。我将不胜AP preciate,如果有人可以给我在C的逻辑/功能这样做。您还可以使用不同的函数原型。
I have 65 parameters of different bit length which I need to fill in an octet string. Parametrs would be filled continuously in octet string. For example, suppose the first parameter is 1 bit long so it would be filled at 0th bit position of 1st octet of the octet string. Now the second parameter is suppose 9 bit long. So the first 7 bits of this parametr would be filled in the same octet and the next 2 bits should go to 0th and 1st bit position of next octet. Similarly other parameters would get filled in the octet string. I tried to write a function where in I passed the pointer to the current octet, the bit position and the source pointer from where data would get copied. But I find difficulty in logic implemetation. I have tried numerous logics(bit operation, bit shifting, rotation etc.) but could not get the correct one. I would greatly appreciate if someone can give me a logic/function in "C" to do so. You can use different function prototype also.
我已经写了code 16位如下:
I have written a code for 16 bit as following:
void set16BitVal(U8** p_buf, U8* bitPos, U16 src)
{
U16 ctr;
U16 bitVal;
U16 srcBitVal;
U16 tempSrc = src;
U8 temp = **p_buf;
printf("\n temp = %d\n", temp);
for(ctr=0; ctr<16; ctr++)
{
bitVal = 1;
bitVal = bitVal << ctr;
srcBitVal = src & bitVal;
temp = temp | srcBitVal;
**p_buf = temp;
if(srcBitVal)
srcBitVal = 1;
else
srcBitVal = 0;
printf("\n bit = %d, p_buf = %x \t p_buf=%d bitPos=%d ctr=%d srcBitVal = %d\n",\
tempSrc, *p_buf, **p_buf, *bitPos, ctr, srcBitVal);
*bitPos = (*bitPos+1)%8; /*wrap around after bitPos:7 */
if(0 == *bitPos)
{
(*p_buf)++; /*jump to next octet*/
temp = **p_buf;
printf("\n Value of temp = %d\n", temp);
}
//printf("\n ctr=%d srcBitVal = %d", ctr, srcBitVal);
printf("\n");
}
}
但问题是,假设如果我通过SRC = 54647,我得到以下输出中:
But the problem is that suppose if I pass src=54647, i get following ouput:
TEMP = 0
位= 54647,P_BUF = bf84da4b P_BUF = 1位位置= 0 CTR = 0 srcBitVal = 1
bit = 54647, p_buf = bf84da4b p_buf=1 bitPos=0 ctr=0 srcBitVal = 1
位= 54647,P_BUF = bf84da4b P_BUF = 3 BITPOS = 1 CTR = 1 srcBitVal = 1
bit = 54647, p_buf = bf84da4b p_buf=3 bitPos=1 ctr=1 srcBitVal = 1
位= 54647,P_BUF = bf84da4b P_BUF = 7 BITPOS = 2 CTR = 2 srcBitVal = 1
bit = 54647, p_buf = bf84da4b p_buf=7 bitPos=2 ctr=2 srcBitVal = 1
位= 54647,P_BUF = bf84da4b P_BUF = 7 BITPOS = 3 CTR = 3 srcBitVal = 0
bit = 54647, p_buf = bf84da4b p_buf=7 bitPos=3 ctr=3 srcBitVal = 0
位= 54647,P_BUF = bf84da4b P_BUF = 23 BITPOS = 4 CTR = 4 srcBitVal = 1
bit = 54647, p_buf = bf84da4b p_buf=23 bitPos=4 ctr=4 srcBitVal = 1
位= 54647,P_BUF = bf84da4b P_BUF = 55 BITPOS = 5 CTR = 5 srcBitVal = 1
bit = 54647, p_buf = bf84da4b p_buf=55 bitPos=5 ctr=5 srcBitVal = 1
位= 54647,P_BUF = bf84da4b P_BUF = 119 = BITPOS 6 CTR = 6 srcBitVal = 1
bit = 54647, p_buf = bf84da4b p_buf=119 bitPos=6 ctr=6 srcBitVal = 1
位= 54647,P_BUF = bf84da4b P_BUF = 119 = BITPOS 7 CTR = 7 srcBitVal = 0
bit = 54647, p_buf = bf84da4b p_buf=119 bitPos=7 ctr=7 srcBitVal = 0
临时的值= 0
位= 54647,P_BUF = bf84da4c P_BUF = 0 BITPOS = 0 CTR = 8 srcBitVal = 1
bit = 54647, p_buf = bf84da4c p_buf=0 bitPos=0 ctr=8 srcBitVal = 1
位= 54647,P_BUF = bf84da4c P_BUF = 0 BITPOS = 1点击率= 9 srcBitVal = 0
bit = 54647, p_buf = bf84da4c p_buf=0 bitPos=1 ctr=9 srcBitVal = 0
位= 54647,P_BUF = bf84da4c P_BUF = 0 BITPOS = 2 CTR = 10 srcBitVal = 1
bit = 54647, p_buf = bf84da4c p_buf=0 bitPos=2 ctr=10 srcBitVal = 1
位= 54647,P_BUF = bf84da4c P_BUF = 0 BITPOS = 3 CTR = 11 srcBitVal = 0
bit = 54647, p_buf = bf84da4c p_buf=0 bitPos=3 ctr=11 srcBitVal = 0
位= 54647,P_BUF = bf84da4c P_BUF = 0 BITPOS = 4 CTR = 12 srcBitVal = 1
bit = 54647, p_buf = bf84da4c p_buf=0 bitPos=4 ctr=12 srcBitVal = 1
位= 54647,P_BUF = bf84da4c P_BUF = 0 BITPOS = 5 CTR = 13 srcBitVal = 0
bit = 54647, p_buf = bf84da4c p_buf=0 bitPos=5 ctr=13 srcBitVal = 0
位= 54647,P_BUF = bf84da4c P_BUF = 0 BITPOS = 6 CTR = 14 srcBitVal = 1
bit = 54647, p_buf = bf84da4c p_buf=0 bitPos=6 ctr=14 srcBitVal = 1
位= 54647,P_BUF = bf84da4c P_BUF = 0 BITPOS = 7 CTR = 15 srcBitVal = 1
bit = 54647, p_buf = bf84da4c p_buf=0 bitPos=7 ctr=15 srcBitVal = 1
临时的值= 0
然而,预期成果是:下一个字节应该开始用起填充值的SRC第8位。
However the expected output is : next byte should start filling with values 8th bit onwards of src.
有人可以帮助我整理出来?
Can someone help me sort it out?
推荐答案
您是幸运的。因为我喜欢位操作,我写了一个通用的实施BitBuffer的只为你。我还没有彻底地(例如不是所有的高难度弯道例)进行测试,但你会看到,它通过简单的测试,我加入到下面的code。
You are lucky. Since I love bit twiddling, I wrote a generic implementation of a BitBuffer just for you. I have not tested it thoroughly (e.g. not all nasty corner cases) but as you will see, it passes the simple tests I added to the code below.
#include <assert.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <stdbool.h>
struct BitBuffer {
unsigned length; // No of bits used in buffer
unsigned capacity; // No of bits available in buffer
uint8_t buffer[];
};
struct BitBuffer * newBitBuffer (
unsigned capacityInBits
) {
int capacityInBytes;
struct BitBuffer * result;
capacityInBytes = (capacityInBits / 8);
if (capacityInBits % 8 != 0) {
capacityInBytes++;
}
result = malloc(sizeof(*result) + capacityInBytes);
if (result) {
result->length = 0;
result->capacity = capacityInBits;
}
return result;
}
bool addBitsToBuffer (
struct BitBuffer * bbuffer, const void * bits, unsigned bitCount
) {
unsigned tmpBuf;
unsigned tmpBufLen;
unsigned tmpBufMask;
uint8_t * nextBufBytePtr;
const uint8_t * nextBitsBytePtr;
// Verify input parameters are sane
if (!bbuffer || !bits) {
// Evil!
return false;
}
if (bitCount == 0) {
// No data to add? Nothing to do.
return true;
}
// Verify we have enough space available
if (bbuffer->length + bitCount > bbuffer->capacity) {
// Won't fit!
return false;
}
// Get the first byte we start writing bits to
nextBufBytePtr = bbuffer->buffer + (bbuffer->length / 8);
// Shortcut:
// If we happen to be at a byte boundary,
// we can simply use memcpy and save us a lot of headache.
if (bbuffer->length % 8 == 0) {
unsigned byteCount;
byteCount = bitCount / 8;
if (bitCount % 8 != 0) {
byteCount++;
}
memcpy(nextBufBytePtr, bits, byteCount);
bbuffer->length += bitCount;
return true;
}
// Let the bit twiddling begin
nextBitsBytePtr = bits;
tmpBuf = *nextBufBytePtr;
tmpBufLen = bbuffer->length % 8;
tmpBuf >>= 8 - tmpBufLen;
tmpBufMask = (~0u) >> ((sizeof(unsigned) * 8) - tmpBufLen);
// tmpBufMask has the first tmpBufLen bits set to 1.
// E.g. "tmpBufLen == 3" ==> "tmpBufMask == 0b111 (7)"
// or "tmpBufLen == 6" ==> "tmpBufMask = 0b111111 (63)", and so on.
// Beyond this point we will neither access bbuffer->length again, nor
// can this function fail anymore, so we set the final length already.
bbuffer->length += bitCount;
// Process input bits in byte chunks as long as possible
while (bitCount >= 8) {
// Add 8 bits to tmpBuf
tmpBuf = (tmpBuf << 8) | *nextBitsBytePtr;
// tmpBuf now has "8 + tmpBufLen" bits set
// Add the highest 8 bits of tmpBuf to our BitBuffer
*nextBufBytePtr = (uint8_t)(tmpBuf >> tmpBufLen);
// Cut off the highest 8 bits of tmpBuf
tmpBuf &= tmpBufMask;
// tmpBuf now has tmpBufLen bits set again
// Skip to next input/output byte
bitCount -= 8;
nextBufBytePtr++;
nextBitsBytePtr++;
}
// Test if we still have bits left. That will be the case
// if the input bit count was no integral multiple of 8.
if (bitCount != 0) {
// Add bitCount bits to tmpBuf
tmpBuf = (tmpBuf << bitCount) | (*nextBitsBytePtr >> (8 - bitCount));
tmpBufLen += bitCount;
}
// tmpBufLen is never 0 here, it must have a value in the range [1, 14].
// We add zero bits to it so that tmpBuf has 16 bits set.
tmpBuf <<= (16 - tmpBufLen);
// Now we only need to add one or two more bytes from tmpBuf to our
// BitBuffer, depending on its length prior to adding the zero bits.
*nextBufBytePtr = (uint8_t)(tmpBuf >> 8);
if (tmpBufLen > 8) {
*(++nextBufBytePtr) = (uint8_t)(tmpBuf & 0xFF);
}
return true;
}
int main ()
{
bool res;
uint8_t testData[4];
struct BitBuffer * buf;
buf = newBitBuffer(1024); // Can hold up to 1024 bits
assert(buf);
// Let's add some test data.
// Add 1 bit "1" => Buffer "1"
testData[0] = 0xFF;
res = addBitsToBuffer(buf, testData, 1);
assert(res);
// Add 6 bits "0101 01" => Buffer "1010 101"
testData[0] = 0x54;
res = addBitsToBuffer(buf, testData, 6);
assert(res);
// Add 4 Bits "1100" => Buffer "1010 1011 100"
testData[0] = 0xC0;
res = addBitsToBuffer(buf, testData, 4);
assert(res);
// Add 16 Bits "0111 1010 0011 0110"
// ==> Buffer "1010 1011 1000 1111 0100 0110 110
testData[0] = 0x7A;
testData[1] = 0x36;
res = addBitsToBuffer(buf, testData, 16);
assert(res);
// Add 5 Bits "0001 1"
// ==> Buffer "1010 1011 1000 1111 0100 0110 1100 0011"
testData[0] = 0x18;
res = addBitsToBuffer(buf, testData, 5);
assert(res);
// Buffer should now have exactly a length of 32 bits
assert(buf->length == 32);
// And it should have the value 0xAB8F46C3
testData[0] = 0xAB;
testData[1] = 0x8F;
testData[2] = 0x46;
testData[3] = 0xC3;
assert(memcmp(buf->buffer, testData, 4) == 0);
free(buf);
return 0;
}
在code未实现最高性能进行了优化,但我想它应该有不俗的表现仍然。任何额外的性能调整将显着增加了code尺寸,我想保持code相当简单。有些人可能会认为,使用&GT;&GT; 3
而不是 / 8
和&安培; 0x7的
而不是%8
将导致更好的表现,但如果你使用一个体面的C编译器,这正是编译器将在内部做无论如何,如果启用了优化,因此我preferred保持code更具可读性来代替。
The code is not optimized for maximum performance, yet I guess it should have a decent performance nonetheless. Any additional performance tweaks would have increased the code size noticeably and I wanted to keep the code rather simple. Some people may argue that using >> 3
instead of / 8
and & 0x7
instead of % 8
will lead to better performance, yet if you use a decent C compiler, that's exactly what the compiler will internally do anyway if you enable optimizations and thus I preferred to keep the code more readable instead.
其他注意结果
当你通过指针多字节的数据类型,观看字节顺序!例如。以下code
Additional Note
When you pass pointers to multi-byte data types, watch the byte order! E.g. the following code
uint16_t x16 = ...;
addBitsToBuffer(buf, &x16, ...);
uint32_t x32 = ...;
addBitsToBuffer(buf, &x32, ...);
大端机(PPC CPU)上工作得很好,但它可能不会给小端计算机上的预期的结果(例如x86处理器)。在小端机器,你就必须先交换字节顺序。您可以使用 htons
和 htonl
为此:
uint16_t x16 = ...;
uint16_t x16be = htons(x16);
addBitsToBuffer(buf, &x16be, ...);
uint32_t x32 = ...;
uint32_t x32be = htonl(x32);
addBitsToBuffer(buf, &x32be, ...);
在大端机器, htonX
函数/宏通常什么也不做,因为该值已经在网络字节顺序(大端),而上一点点endian机器他们将交换的字节顺序。
On a big endian machine, htonX
functions/macros usually do nothing, since the value is already in "network byte order" (big endian), while on a little endian machine they will swap the byte order.
传递一个uint8_t有指针总是要么机器上工作,它只是一个字节,因此不存在字节顺序。
Passing an uint8_t pointer will always work on either machine, it is only a single byte, hence there is no byte order.
这篇关于灌装字节串的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!