将uint8_t *缓冲区转换为uint16_t并更改字节序

问题描述 投票:0回答:2

我想处理由外部库提供的数据。

lib保存数据并提供对它的访问,如下所示:

const uint8_t* data;
std::pair<const uint8_t*, const uint8_t*> getvalue() const {
  return std::make_pair(data + offset, data + length);
}

我知道当前数据包含两个uint16_t数字,但是我需要更改其字节序。因此,数据总共为4个字节长,并包含以下数字:

66 4 0 0

所以我想分别用uint16_t1090值得到两个0数字。

我可以进行基本算术并在一处更改字节序:

pair<const uint8_t*, const uint8_t*> dataPtrs = library.value();
vector<uint8_t> data(dataPtrs.first, dataPtrs.second);

uint16_t first = data[1] <<8 + data[0]
uint16_t second = data[3]<<8 + data[2]

但是我想做些更优雅的事情(如果有更好的方法获得uint16_t,则向量是可替换的。

如何更好地从uint16_t创建uint8_t*?如果可能的话,我会避免使用memcpy,而应使用更现代/安全的方法。

Boost具有一些不错的仅标头的字节序library,它可以工作,但是需要uint16_t输入。

为了更进一步,Boost还提供了用于更改字节序的数据类型,因此我可以创建一个结构:

struct datatype {
    big_int16_buf_t     data1;
    big_int16_buf_t     data2;
}

是否可以安全地(填充,平台相关性等)将有效的4字节长的uint8_t*强制转换为datatype?也许有这样的工会?

typedef union {
    uint8_t u8[4];
    datatype correct_data;
} mydata;
c++ endianness uint8t uint16
2个回答
1
投票

也许有这样的结合?

没有在C ++中,对带有联合的类型修剪没有很好的定义。

这将起作用:

datatype d{};
std::memcpy(&d, data, sizeof d);

请注意,这将导致不同的值,具体取决于CPU的本地字节顺序。对于便携性而言,这不是理想的选择。

uint16_t first = data[1] <<8 + data[0]
uint16_t second = data[3]<<8 + data[2]

但是我想做些更优雅的事情

实际上(主观上,我认为)这是最优雅的方式,因为它在所有系统上都以相同的方式工作。这会将数据读取为小端,无论CPU是小端,大端还是其他端。这是便携式的。

但是我想做些更优雅的事情(如果有更好的方法来获取uint16_ts,向量是可替换的。

矢量似乎完全没有意义。您也可以使用:

const std::uint8_t* data = dataPtrs.first;

0
投票

如何更好地从uint16_t创建uint8_t*

如果您确定 uint8_t指针后面的数据确实是uint16_t,则C ++允许:auto u16 = *static_cast<uint16_t const*>(data); 否则,这是UB。

给出一个大的endian值,可以使用ntohs函数将该值转换为小字节序(在Linux下,其他OS具有类似的功能)。


但是请注意,如果您持有的指针指向两个单独的ntohs值,则您[[必须通过指针转换对其进行转换。在这种情况下,您必须手动指定哪个值到达何处(可以使用功能模板)。这将是最可移植的解决方案,并且编译器很可能会根据移位和错误创建有效的代码。

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