将 1-32 位插入 64 位(8x8 字节)缓冲区
Inserting 1-32 bits into a 64 bit (8x8byte) buffer
我正在尝试将 1 到 32 位长的值插入到 8 字节(64 位)的缓冲区中。
例如,我有 12 位值,我想将其插入位位置 7 到 18。
我能想到的唯一方法是将我的 12 位值转换为 64 位值,移动它,然后以这种方式设置缓冲区中的所有位,然后将我的 64 位值分成 8字节。 8 字节帧中可能还有其他数据... 有更好的方法吗?
下面将包含一些示例代码。
byte tx_msg[8] = {0};
uint32_t random_value = 77;
uint64_t buffer = 0;
// In this example, start point is bit 7, length is 12.
buffer = (uint64_t)random_value << (64 - 12 - 7);
for(int i = 0; i < 8; i++) {
tx_msg[7-i] = tx_msg[7-i] | buffer >> (i*8);
}
首先你需要明确定义位序。假设位排序 LSB 在前:
| Byte0 | Byte1 | ...
-----------------------
|01234567|01234567| ...
例如:
|00000001|10000000|
将是 Byte0 == 0x80
和 Byte1 == 0x08
(因为十六进制表示是 MSB 在前)。
那么我会建议一个更通用的接口:
void copyBits( uint8_t* dest, int offset, uint32_t bits, int length ) ;
其中 bits
中的 length
位(从 LSB 开始)将被复制到 dest
.
中的 offset
位
一个简单的(但在性能方面不是最优的)方法是逐位复制:
#include <stdint.h>
#include <stdlib.h>
void copyBits( uint8_t* dest, int offset, uint32_t bits, int length )
{
for( int b = 0; b < length; b++ )
{
int source_bit = (bits & (0x01 << b)) == 0 ? 0 : 1 ;
div_t bit_dest = div( offset + b, 8 ) ;
if( source_bit == 0 )
{
dest[bit_dest.quot] &= ~(0x01 << bit_dest.rem) ;
}
else
{
dest[bit_dest.quot] |= (0x01 << bit_dest.rem) ;
}
}
}
这可以通过使用整个字节并在头部和尾部进行屏蔽来改进,但它更复杂,所以除非性能很关键或者你经常复制很多位,否则我建议简单和通用可能是充足的。无论哪种方式,带回家的是函数的通用可重用性,而不是针对特定参数的硬编码。重要的是它不限于 64 位目标缓冲区。它可以进行调整,因此它不限于最大 32 位源字段。
用法示例:
uint8_t x[8] = {0};
insertBits( x, 7, 0x555, 12 ) ;
for( int i = 0; i < sizeof( x ); i++ )
{
printf( "%02X", x[i] ) ;
}
结果
80AA020000000000
二进制中 LSB 的第一位顺序是:
LSB --->
0000 0001 0101 0101 0100 0000 0000 ...
^-------------^
0x555 (12 bits) copied here
我正在尝试将 1 到 32 位长的值插入到 8 字节(64 位)的缓冲区中。
例如,我有 12 位值,我想将其插入位位置 7 到 18。
我能想到的唯一方法是将我的 12 位值转换为 64 位值,移动它,然后以这种方式设置缓冲区中的所有位,然后将我的 64 位值分成 8字节。 8 字节帧中可能还有其他数据... 有更好的方法吗?
下面将包含一些示例代码。
byte tx_msg[8] = {0};
uint32_t random_value = 77;
uint64_t buffer = 0;
// In this example, start point is bit 7, length is 12.
buffer = (uint64_t)random_value << (64 - 12 - 7);
for(int i = 0; i < 8; i++) {
tx_msg[7-i] = tx_msg[7-i] | buffer >> (i*8);
}
首先你需要明确定义位序。假设位排序 LSB 在前:
| Byte0 | Byte1 | ...
-----------------------
|01234567|01234567| ...
例如:
|00000001|10000000|
将是 Byte0 == 0x80
和 Byte1 == 0x08
(因为十六进制表示是 MSB 在前)。
那么我会建议一个更通用的接口:
void copyBits( uint8_t* dest, int offset, uint32_t bits, int length ) ;
其中 bits
中的 length
位(从 LSB 开始)将被复制到 dest
.
offset
位
一个简单的(但在性能方面不是最优的)方法是逐位复制:
#include <stdint.h>
#include <stdlib.h>
void copyBits( uint8_t* dest, int offset, uint32_t bits, int length )
{
for( int b = 0; b < length; b++ )
{
int source_bit = (bits & (0x01 << b)) == 0 ? 0 : 1 ;
div_t bit_dest = div( offset + b, 8 ) ;
if( source_bit == 0 )
{
dest[bit_dest.quot] &= ~(0x01 << bit_dest.rem) ;
}
else
{
dest[bit_dest.quot] |= (0x01 << bit_dest.rem) ;
}
}
}
这可以通过使用整个字节并在头部和尾部进行屏蔽来改进,但它更复杂,所以除非性能很关键或者你经常复制很多位,否则我建议简单和通用可能是充足的。无论哪种方式,带回家的是函数的通用可重用性,而不是针对特定参数的硬编码。重要的是它不限于 64 位目标缓冲区。它可以进行调整,因此它不限于最大 32 位源字段。
用法示例:
uint8_t x[8] = {0};
insertBits( x, 7, 0x555, 12 ) ;
for( int i = 0; i < sizeof( x ); i++ )
{
printf( "%02X", x[i] ) ;
}
结果
80AA020000000000
二进制中 LSB 的第一位顺序是:
LSB --->
0000 0001 0101 0101 0100 0000 0000 ...
^-------------^
0x555 (12 bits) copied here