将 uint8_t* 缓冲区转换为 uint16_t 并更改字节顺序
Converting uint8_t* buffer to uint16_t and changing endianness
我想处理外部图书馆提供的数据。
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
值分别为 1090
和 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
s,向量是可替换的)。
如何更好地从 uint8_t*
创建 uint16_t
?如果可能的话,我会避免使用 memcpy,并使用更多 modern/safe.
Boost 有一些不错的 header-only endian library 可以工作,但它需要一个 uint16_t
输入。
为了更进一步,Boost 还提供了用于更改字节顺序的数据类型,因此我可以创建一个结构:
struct datatype {
big_int16_buf_t data1;
big_int16_buf_t data2;
}
是否可以安全地(填充、platform-dependency 等)将有效的 4 字节长 uint8_t*
转换为 datatype
?也许有像这个工会这样的东西?
typedef union {
uint8_t u8[4];
datatype correct_data;
} mydata;
Maybe with something like this union?
没有。 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]
However I'd like to do something more elegant
这实际上(在我看来主观上)是一种非常优雅的方式,因为它在所有系统上都以相同的方式工作。这会将数据读取为小字节序,无论 CPU 是小字节序、大字节序还是其他字节序。这很好携带。
However I'd like to do something more elegant (the vector is replaceable if there is better way for getting the uint16_ts).
矢量似乎完全没有意义。您也可以使用:
const std::uint8_t* data = dataPtrs.first;
How can I better create uint16_t
from uint8_t*
?
如果您确定 uint8_t
指针后面的数据确实是 uint16_t
,C++ 允许:auto u16 = *static_cast<uint16_t const*>(data);
否则就是UB.
鉴于 endian value, transforming this into little endian can be done with the ntohs
功能强大(在 linux 下,其他操作系统也有类似的功能)。
但要注意,如果您持有的指针指向两个单独的 uint8_t
值,您绝不能 转换它们通过指针转换。在这种情况下,您必须手动指定哪个值去哪里(可以想象使用函数模板)。这将是最便携的解决方案,而且编译器很可能会根据 shifts 和 ors 创建高效的代码。
我想处理外部图书馆提供的数据。
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
值分别为 1090
和 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
s,向量是可替换的)。
如何更好地从 uint8_t*
创建 uint16_t
?如果可能的话,我会避免使用 memcpy,并使用更多 modern/safe.
Boost 有一些不错的 header-only endian library 可以工作,但它需要一个 uint16_t
输入。
为了更进一步,Boost 还提供了用于更改字节顺序的数据类型,因此我可以创建一个结构:
struct datatype {
big_int16_buf_t data1;
big_int16_buf_t data2;
}
是否可以安全地(填充、platform-dependency 等)将有效的 4 字节长 uint8_t*
转换为 datatype
?也许有像这个工会这样的东西?
typedef union {
uint8_t u8[4];
datatype correct_data;
} mydata;
Maybe with something like this union?
没有。 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]
However I'd like to do something more elegant
这实际上(在我看来主观上)是一种非常优雅的方式,因为它在所有系统上都以相同的方式工作。这会将数据读取为小字节序,无论 CPU 是小字节序、大字节序还是其他字节序。这很好携带。
However I'd like to do something more elegant (the vector is replaceable if there is better way for getting the uint16_ts).
矢量似乎完全没有意义。您也可以使用:
const std::uint8_t* data = dataPtrs.first;
How can I better create
uint16_t
fromuint8_t*
?
如果您确定 uint8_t
指针后面的数据确实是 uint16_t
,C++ 允许:auto u16 = *static_cast<uint16_t const*>(data);
否则就是UB.
鉴于 endian value, transforming this into little endian can be done with the ntohs
功能强大(在 linux 下,其他操作系统也有类似的功能)。
但要注意,如果您持有的指针指向两个单独的 uint8_t
值,您绝不能 转换它们通过指针转换。在这种情况下,您必须手动指定哪个值去哪里(可以想象使用函数模板)。这将是最便携的解决方案,而且编译器很可能会根据 shifts 和 ors 创建高效的代码。