0

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

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_t数字10900值。

我可以做基本的算术,并在一个地方改变字节顺序:

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_ts,那么向量是可替换的)。

我怎样才能更好地uint16_t创造uint8_t*?如果可能的话,我会避免使用 memcpy,并使用更现代/更安全的东西。

Boost 有一些不错的仅包含标头的字节序,它可以工作,但它需要一个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;
4

2 回答 2

2

也许有像这个工会这样的东西?

不。在 C++ 中没有很好地定义带有联合的类型双关语。

假设这是可行的big_int16_buf_t,因此datatype可以轻松复制:

datatype d{};
std::memcpy(&d, data, sizeof d);
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;
于 2020-06-11T13:52:57.850 回答
0

我怎样才能更好地uint16_t创造uint8_t*

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

给定一个大端值,将其转换为小端可以使用该ntohs函数完成(在linux下,其他操作系统具有类似的功能)。


但请注意,如果您持有的指针指向两个单独的uint8_t值,则不能通过指针转换来转换它们。在这种情况下,您必须手动指定哪个值在哪里(可以使用函数模板)。这将是最可移植的解决方案,并且编译器很可能会从移位和 ors 中创建高效的代码。

于 2020-06-11T14:11:46.023 回答