从uint8_t数组中获取uint16_t会得出错误的结果?

时间:2019-03-21 12:29:38

标签: c

我有一个字节数组:

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会反转字节的位置,这不是大字节序/小字节序的问题,因为这是前8位与8秒倒置的结果。

我只是期望uint16_t在给定位置取16位,然后在此处返回18。

有人可以告诉我我在做什么错吗?

2 个答案:

答案 0 :(得分:3)

  

我不明白为什么get_U16会反转字节的位置,这不是大字节序/小字节序的问题,因为这里是前8位和8秒倒置了。

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

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

答案 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并使用移位和仅移位。

  

这不是大字节序/小字节序的问题,因为这里是前8位与8秒倒置的

简而言之:正是确切耐力的原理。它将前8位转换为后8位。

  

任何人都可以告诉我我做错了什么吗?

您没有做错任何事情,您的代码可能会按原样工作。