通常可以从uint64_t
检索uint32_t
或uint16_t
/ char* buf
等,如下所示:
uint32_t val = *(uint32_t*) buf;
但现在假设buf
是char [6]
,如何从中检索数值?
*无符号大端(网络字节顺序)
答案 0 :(得分:2)
一种便携且符合标准的方式(与指针转换或memcpy相反)将使其明确:
uint64_t val = 0;
for (int i = 0; i < 6; ++i)
val |= (uint64_t)(unsigned char)buf[i] << (8*(6-i-1));
这假设是大端(网络字节顺序)。如果您的输入数组已经是unsigned char
类型,则unsigned char*
的额外强制转换就是您不需要的。
答案 1 :(得分:0)
使用uint64_t val = 0; memcpy(&val, buf, 6);
但要注意字节序问题(这个问题适用于小尾数val和buf)。
另一种避免丑陋演员的方法是使用联盟:
union {
uint64_t u64;
uint8_t c[8];
} foo;
按正确顺序将字节写入foo.c[]
,然后访问foo.u64
。不是100%ISO C Kosher,但在大多数现代C实现中都是正确的。
答案 2 :(得分:0)
我不会问你是如何得到一个大端的六字节缓冲区。
const int odd_buffer_size = 6;
char src[ odd_buffer_size ] = { … };
uint64_t dst = 0;
// Copy the big-endian data into a big-endian long:
memcpy( ( (char*) & dst ) + 2, src, odd_buffer_size );
// Read the data as a value (aliasing-safe) and convert endianness:
dst = ntohll( dst );
ntohll
不是标准C,但可以在Windows中使用,有时在Linux上可用。它的名称似乎因平台而异(例如be64toh
),但某些设施始终可用。
顺便说一句,技巧uint32_t val = *(uint32_t*) buf;
是不安全的,因为缓冲区可能(在这种特殊情况下,几乎肯定是)不正确地对齐以访问uint32_t
值。
即使形成具有奇数地址的uint32_t *
类型的值,也足以在C中崩溃。在重新解释字节时,请始终使用memcpy
或union
。