问题描述
如果要将 uint64_t
转换为 uint8_t [8]
(小尾数)。在小端字节体系结构上,您只能执行难看的 reinterpret_cast<>
或 memcpy()
,例如:
If you want to convert uint64_t
to a uint8_t[8]
(little endian). On a little endian architecture you can just do an ugly reinterpret_cast<>
or memcpy()
, e.g:
void from_memcpy(const std::uint64_t &x, uint8_t* bytes) {
std::memcpy(bytes, &x, sizeof(x));
}
这会产生有效的汇编:
mov rax, qword ptr [rdi]
mov qword ptr [rsi], rax
ret
但是它不是便携式的。
However it is not portable. It will have different behaviour on a little endian machine.
用于将 uint8_t [8]
转换为 uint64_t
有一个很好的解决方案-只需执行以下操作即可:
For converting uint8_t[8]
to uint64_t
there is a great solution - just do this:
void to(const std::uint8_t* bytes, std::uint64_t &x) {
x = (std::uint64_t(bytes[0]) << 8*0) |
(std::uint64_t(bytes[1]) << 8*1) |
(std::uint64_t(bytes[2]) << 8*2) |
(std::uint64_t(bytes[3]) << 8*3) |
(std::uint64_t(bytes[4]) << 8*4) |
(std::uint64_t(bytes[5]) << 8*5) |
(std::uint64_t(bytes[6]) << 8*6) |
(std::uint64_t(bytes[7]) << 8*7);
}
这看起来效率低下,但实际上使用Clang -O2
会生成与以前完全相同的程序集,如果在大型字节序计算机上进行编译,它将足够聪明以使用本机字节交换指令。例如。这段代码:
This looks inefficient but actually with Clang -O2
it generates exactly the same assembly as before, and if you compile on a big endian machine it will be smart enough to use a native byte swap instruction. E.g. this code:
void to(const std::uint8_t* bytes, std::uint64_t &x) {
x = (std::uint64_t(bytes[7]) << 8*0) |
(std::uint64_t(bytes[6]) << 8*1) |
(std::uint64_t(bytes[5]) << 8*2) |
(std::uint64_t(bytes[4]) << 8*3) |
(std::uint64_t(bytes[3]) << 8*4) |
(std::uint64_t(bytes[2]) << 8*5) |
(std::uint64_t(bytes[1]) << 8*6) |
(std::uint64_t(bytes[0]) << 8*7);
}
编译为:
mov rax, qword ptr [rdi]
bswap rax
mov qword ptr [rsi], rax
ret
我的问题是:是否存在等效的可靠优化的构造,可用于反向转换?我已经尝试过了,但是天真地编译了它:
My question is: is there an equivalent reliably-optimised construct for converting in the opposite direction? I've tried this, but it gets compiled naively:
void from(const std::uint64_t &x, uint8_t* bytes) {
bytes[0] = x >> 8*0;
bytes[1] = x >> 8*1;
bytes[2] = x >> 8*2;
bytes[3] = x >> 8*3;
bytes[4] = x >> 8*4;
bytes[5] = x >> 8*5;
bytes[6] = x >> 8*6;
bytes[7] = x >> 8*7;
}
编辑:经过一些试验,此代码可以只要使用 uint8_t * __restrict__个字节
,就可以在GCC 8.1和更高版本中进行最佳编译。但是我仍然没有找到Clang可以优化的形式。
After some experimentation, this code does get compiled optimally with GCC 8.1 and later as long as you use uint8_t* __restrict__ bytes
. However I still haven't managed to find a form that Clang will optimise.
推荐答案
返回值如何?
易于推理和小型汇编:
What about returning a value?Easy to reason about and small assembly:
#include <cstdint>
#include <array>
auto to_bytes(std::uint64_t x)
{
std::array<std::uint8_t, 8> b;
b[0] = x >> 8*0;
b[1] = x >> 8*1;
b[2] = x >> 8*2;
b[3] = x >> 8*3;
b[4] = x >> 8*4;
b[5] = x >> 8*5;
b[6] = x >> 8*6;
b[7] = x >> 8*7;
return b;
}
和大字节序:
#include <stdint.h>
struct mybytearray
{
uint8_t bytes[8];
};
auto to_bytes(uint64_t x)
{
mybytearray b;
b.bytes[0] = x >> 8*0;
b.bytes[1] = x >> 8*1;
b.bytes[2] = x >> 8*2;
b.bytes[3] = x >> 8*3;
b.bytes[4] = x >> 8*4;
b.bytes[5] = x >> 8*5;
b.bytes[6] = x >> 8*6;
b.bytes[7] = x >> 8*7;
return b;
}
(std :: array无法用于-target aarch64_be吗? )
(std::array not available for -target aarch64_be? )
这篇关于在Clang中将uint64_t转换为字节数组并进行最佳移植的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!