从uint8_t数组中取出uint16_t给出错误的结果?

问题描述 投票:-1回答:2

我有一个字节数组:

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位。

谁能告诉我我做错了什么?

c
2个回答
3
投票

我不明白为什么get_U16正在反转字节的位置,并且它不是大端/小端问题,因为这里是与8秒位反转的前8位。

这是不正确的。 Endianess关注较大数据类型中的字节顺序。在这种情况下,最低有效字节似乎存储在最低地址。

当您读取p的索引2的地址(称为uint16_t)时,该地址的内存包含该值的低字节。地址p + 1包含值的高位字节。


2
投票

你应该手动处理一切。

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位。

谁能告诉我我做错了什么?

你没有做错什么,你的代码可能会按原样运行。

© www.soinside.com 2019 - 2024. All rights reserved.