我有一个字节数组:
uint8_t* data = 10101010 01000001 00000000 00010010 00000000 00000010..........
uint8_t get_U8(uint8_t * data, int* offset)
{
uint8_t tmp = *((uint8_t*)(data + *offset));
*offset += sizeof(uint8_t);
return tmp;
}
uint16_t get_U16(uint8_t* data, int* offset)
{
uint16_t tmp = *((uint16_t*)(data + *offset));
*offset += sizeof(uint16_t);
return tmp;
}
这里的偏移是2。
get_U8(data, 0) = 10101010 = 170 ===> OK
get_U8(data, 1) = 01000001 = 65 ===> OK
get_U8(data, 2) = 00000000 = 0 ===> OK
get_U8(data, 3) = 00010010 = 18 ===> OK
但
get_U16(data, 2) = 4608 ===> NOT OK (should be 18)
4608 = 00010010 00000000
所以我理解2个字节是反转的。
我不明白为什么get_U16
正在反转字节的位置,并且它不是一个大的endian / little endian问题,因为这里是与8秒位反转的前8位。
我只是期待uint16_t
在给定位置取16位,然后在这里返回18位。
谁能告诉我我做错了什么?
我不明白为什么get_U16正在反转字节的位置,并且它不是大端/小端问题,因为这里是与8秒位反转的前8位。
这是不正确的。 Endianess关注较大数据类型中的字节顺序。在这种情况下,最低有效字节似乎存储在最低地址。
当您读取p
的索引2的地址(称为uint16_t
)时,该地址的内存包含该值的低字节。地址p + 1
包含值的高位字节。
你应该手动处理一切。
uint8_t get_U8(uint8_t * data, int* offset)
{
uint8_t tmp;
# I think the following should work even on systems where `sizeof(uint8_t) != 1`
memcpy(&tmp, &((unsigned char*)data)[*offset], sizeof(uint8_t));
*offset += sizeof(uint8_t);
return tmp;
}
uint16_t get_U16(uint8_t* data, int* offset)
{
uint8_t tmp1 = get_U8(data, offset);
uint8_t tmp2 = get_U8(data, offset);
uint16_t tmp = tmp1 << 16 | tmp2;
# or tmp = tmp2 << 16 | tmp1; depending on the endianess you want to have
return tmp;
}
这样做:
uint16_t tmp = *((uint16_t*)(data + *offset));
很糟糕,非常糟糕的缓冲你*offset +=
手动转移。如果data + *offset
不是uint16_t
对齐,它很容易导致未定义的行为(读作:分段错误)。不要这样做。你想从两个字节的uint16_t
?通过char读取char并使用位移和仅位移位。
它不是big endian / little endian问题,因为这里是8位反转的前8位。
简而言之:这就是endianess的工作原理。它将前8位反转为后8位。
谁能告诉我我做错了什么?
你没有做错什么,你的代码可能会按原样运行。