如何在具有8位成员的队列中前进,并将耦合组合为16位值
How to advance in a queue with 8-bit members and combine couples into 16-bit values
我有一个指向数组的指针,该数组包含四对8位值,比如这个
MSB-lsb-MSB-lsb-MSB-lsb-MSB-lsb
^
|
bufPointer
我将在这个队列中前进,并用这四个8位对填充fooStruct
结构的16位成员。
我可以为第一位成员分两行完成这项工作:
fooStruct.M1 = *bufPointer << 8;
fooStruct.M1 |= *++bufPointer;
等等
所以,如果我们有
MSB = 0x22;
lsb = 0x37;
hence => fooStrct.M1 = 0x2237;
有可能在一个班轮里做到这一点吗?
为什么选择One Liner真的没有什么特别的原因。学习+好奇心/方便时将来使用。:)
是的,你可以在一行中完成,但为了避免序列点警告,最好这样做:
c = (*p << 8) | *(p + 1);
示例:
#include <stdio.h>
#if defined(__LP64__) || defined(_LP64)
# define BUILD_64 1
#endif
#ifdef BUILD_64
# define BITS_PER_LONG 64
#else
# define BITS_PER_LONG 32
#endif
char *binpad (unsigned long n, size_t sz);
int main (void) {
unsigned char a[] = { 65, 28, 59, 15 };
unsigned char *p = NULL;
unsigned char *end = a + sizeof a/sizeof *a;
unsigned short c = 0;
for (p = a; p < end; p += 2)
{
c = (*p << 8) | *(p + 1);
printf ("n *p : %6hhu (%s)n", *p, binpad (*p, 16));
printf (" *(p + 1) : %6hhu (%s)n", *(p + 1), binpad (*(p + 1), 16));
printf ("n c : %6hu (%s)n", c, binpad (c, 16));
}
return 0;
}
char *binpad (unsigned long n, size_t sz)
{
static char s[BITS_PER_LONG + 1] = {0};
char *p = s + BITS_PER_LONG;
register size_t i;
for (i = 0; i < sz; i++)
*(--p) = (n>>i & 1) ? '1' : '0';
return p;
}
输出
$ ./bin/uchar2short
*p : 65 (0000000001000001)
*(p + 1) : 28 (0000000000011100)
c : 16668 (0100000100011100)
*p : 59 (0000000000111011)
*(p + 1) : 15 (0000000000001111)
c : 15119 (0011101100001111)
为什么在一行中完成它如此重要?
无论如何,这是一种方式:
fooStruct.M1 = (bufPointer += 2, (bufPointer[-2] << 8) | bufPointer[-1]);
由于您使用的是C++,因此可以将缓冲区封装在更智能的"读取器"中。
class Reader
{
public:
Reader(char* bufPointer)
: m_bufPointer(bufPointer) {}
short shortBE()
{
short result = (m_bufPointer[0] << 8) | m_bufPointer[1];
m_bufPointer += 2;
return result;
}
short shortLE()
{
short result = (m_bufPointer[1] << 8) | m_bufPointer[0];
m_bufPointer += 2;
return result;
}
// etc...
};
FooStruct DeserializeFooStruct(char* bufPointer)
{
Reader rd(bufPointer);
FooStruct fooStruct;
fooStruct.M1 = rd.shortBE();
fooStruct.M2 = rd.shortBE();
// and so on
return fooStruct;
}
这种方法的一个优点是,您还可以添加错误检查。例如,如果您携带缓冲区的长度,您可以检查确保没有代码试图读取超过缓冲区的末尾,并且仍然为调用程序保留一行代码。
当然,您可以在一行中完成。但我会质疑为什么,因为当代码被塞进更少的行时,它的可读性总是会降低。编译器并不关心您是在一个或多个中执行此操作。
我认为,最可读的一句话是每次递增:
fooStruct.M1 = (*bufPointer++ << 8) | *bufPointer++;
但有些人可能会对此表示反对
[注意,根据下面的评论,以上内容已删除。我的建议很糟糕!其他答案包含避免序列点问题的一行代码]
我个人的编码风格是明确我正在寻址一个记录并使用它的片段:
fooStruct.M1 = (bufPointer[0] << 8) | bufPointer[1];
bufPointer += 2;
但这当然是两条线。。。任何称职的编译器都应该为这两种变体生成相同的程序集。
只是事后编辑。。。从你的答案中的字里行间,我猜你希望这个代码是紧凑的,因为你正在分配单独的结构元素,而不能在循环中这样做。在这种情况下:
fooStruct.M1 = (bufPointer[0] << 8) | bufPointer[1];
fooStruct.M2 = (bufPointer[2] << 8) | bufPointer[3];
fooStruct.M3 = (bufPointer[4] << 8) | bufPointer[5];
fooStruct.M4 = (bufPointer[6] << 8) | bufPointer[7];
bufPointer += 8; // Only if you need to keep deserialising
接受答案的微小变化:
c = (p[0] << 8) | p[1];
如果你在一台big-endian机器上,你的数据在16位边界对齐,或者支持未对齐的访问,那么你可以简单地:
c = *(short*)p;
相关文章:
- 将浮动的heightmap数组导出为16位原始值
- 宽度为奇数的16位纹理为片状
- OpenGL 16 位模板缓冲区?
- 为什么将双精度转换为 int 似乎在第 16 位数字之后将其四舍五入?
- 16 位到 10 位转换代码说明
- CreateDIBSection为同一图像返回不一致的位图位值
- OpenCV矩阵奇怪的加法,乘法与浮点数和8位值
- AVX2 整数乘以有符号 8 位元素,产生有符号 16 位结果?
- C++将 16 位值转换为 32 位值
- 24 位地址和 24 位算术与 24 位地址与 16 位地址算术之间的区别?
- 16 位系统中的程序如何访问大于 65535 的整数,但不能访问地址
- 使用 SIMD 基于另一个矢量位值计算值的乘积
- 将 Uint8(浮点AUDIO_F32)转换为int16_t(16 位 PCM)
- CCITT CRC 16位启动值0xffff
- 仅使用位操作(不使用分支)将16位带符号值约束在0和4095之间
- 将两个8位的bitset赋值给一个16位的bitset
- 将两个字节转换为16位值的最有效方法
- 需要一个散列函数来创建ipv6 16字节地址和TCP 2字节端口号的32位值
- 如何在具有8位成员的队列中前进,并将耦合组合为16位值
- 如何在C++中将16位十六进制颜色转换为RGB888值