将无符号Char*转换为uint16_t*



我有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)对齐。如果编译器碰巧生成的代码不会因为未对齐的访问而导致硬故障,则结果取决于目标机器的端序。但无论如何,这只是未定义的行为。

如果要使用操作系统的标头,则有可以交换字节的ntohshtons函数。

否则,添加是微不足道的

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

这仅适用于普通旧数据类型,如uint64uint32uint16int64int32int16floatdouble

正如@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]);

最新更新