我有unsigned char * data
,如下所示:
unsigned char * data = ...;
data[0]=0x24;
data[1]=0x8A;
data[2]=0x07;
data[3]=0x75;
我想用以下代码将其转换为uint16_t
:
uint16_t *res= (uint16_t*)(data);
输出为:
res[0]= 0x8A24; res[1]=0x7507
但我希望res变成这样:
res[0]=0x248A; res[1]=0x0775;
如何更改代码?
但我希望res变成这样:
如何更改代码?
这只是:
res[0] = data[0] << 8 | data[1];
res[1] = data[2] << 8 | data[3];
我想用下面的代码将其转换为uint16_t:
uint16_t *res= (uint16_t*)(data);
输出为:
这样的代码将无效,并且取消引用res
会导致未定义的行为。这是严格的别名冲突,并且data
可能不与alignof(uint16_t)
对齐。如果编译器碰巧生成的代码不会因为未对齐的访问而导致硬故障,则结果取决于目标机器的端序。但无论如何,这只是未定义的行为。
如果要使用操作系统的标头,则有可以交换字节的ntohs
和htons
函数。
否则,添加是微不足道的
template <T> T swap_endianness(T in) {
unsigned char array[sizeof(in)] = {};
std::memcpy(array, &in, sizeof(in));
// Byte swap now
for (size_t i = 0; i < sizeof(in)/2; i++)
std::swap(array[i], array[sizeof(in) - i - 1]);
std::memcpy(&in, array, sizeof(in));
return in;
}
用法是:
uint16_t *res= (uint16_t*)(data); // This is undefined behavior. Use memcpy instead.
res[0] = swap_endianness(res[0]); // and so on
这仅适用于普通旧数据类型,如uint64
、uint32
、uint16
、int64
、int32
、int16
、float
、double
。
正如@KamilCuk所指出的,如果data
恰好没有在16位边界对齐,那么类似的(uint16_t *)(data)
可能会导致问题,并且当您在ARM等平台上取消引用它时,可能会导致内存访问错误。正确的解决方案是像这样使用memcpy
:
uint16_t res[2];
std::memcpy(res, data, sizeof(res));
res[0] = swap_endianness(res[0]);
res[1] = swap_endianness(res[1]);