如何将6字节数组转换为数值?

时间:2014-02-28 16:54:21

标签: c pointers casting

通常可以从uint64_t检索uint32_tuint16_t / char* buf等,如下所示:

uint32_t val = *(uint32_t*) buf;

但现在假设bufchar [6],如何从中检索数值?

*无符号大端(网络字节顺序)

3 个答案:

答案 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中崩溃。在重新解释字节时,请始终使用memcpyunion