如何将几个变量复制到其他变量

How to copy few variables to other variable?

本文关键字:变量 几个 复制 其他      更新时间:2023-10-16

例如,

struct Foo
{
Foo(uint8_t b0, uint8_t b1, uint16_t b23)
{
// some code here
}
uint32_t m_n;
};

我可以写这样的东西:

auto dest = reinterpret_cast<uint8_t*>(&m_n);
memcpy(dest, &b0, sizeof(b0));
memcpy(dest + sizeof(b0), &b1, sizeof(b1));
memcpy(dest + sizeof(b0) + sizeof(b1), &b23, sizeof(b23));

但它非常丑陋。当有15个这样的变量时该怎么办(不要问为什么(

我怀疑您需要这种函数:

template<typename T>
std::enable_if_t<std::is_integral_v<T>, std::array<uint8_t, sizeof(T)>>
littleEndianBytes(T value)
{
static_assert(sizeof(uint8_t) == 1);
using result_type = std::array<uint8_t, sizeof(T)>;
result_type result;
for(auto& x : result) {
x = value & 0xFF;
value >>= 8;
}
return result;
}

https://wandbox.org/permlink/ooGuIzZaw8tdffaT

在您展示的特定情况下,您可以使用移位(如注释中所建议的(和逻辑"或"运算将给定的参数移动到目标中,这将给出如下代码:

m_n = (b23 << 16) | (b1 << 8) | b0;

但这是非常具体的情况,你已经给出。如果您的其他变量有不同的类型和/或您想以不同的方式复制内容,则必须调整代码以适应每种用途。

另一种方法(使用相同的例子(,但更容易适应不同的目标类型,是这样的:

uint8_t bytes[4] = { b0, b1, uint8_t(b23 & 0xFF), uint8_t(b23 >> 8) };
memcpy(&m_n, bytes, 4);

首先将字节数组初始化为给定的参数(可以很容易地增加到16个字节(,然后使用memcpy将字节数组移动到目标中。

后一种方法可以通过使bytes成为Foo的成员并在初始值设定项列表中设置其值来进一步"优化":

struct Foo
{
Foo(uint8_t b0, uint8_t b1, uint16_t b23) : bytes{ b0, b1, uint8_t(b23 & 0xFF), uint8_t(b23 >> 8) }
{
memcpy(&m_n, bytes, 4);
}
uint8_t bytes[4];
uint32_t m_n;
};

请随时要求进一步澄清和/或解释。

可能的实现(需要C++17,或参见下文(:

template<typename T, typename... Ts>
constexpr void combine_as_bits_impl(std::size_t offset, unsigned char* out, 
const T& x, const Ts&... xs) {
std::memcpy(out + offset, &x, sizeof(T));
if constexpr (sizeof...(Ts) > 0)
combine_as_bits_impl(offset + sizeof(T), out, xs...);
}
template<typename Out, typename... Ts>
constexpr Out combine_as_bits(const Ts&... xs) {
static_assert((sizeof(Ts) + ...) == sizeof(Out));
unsigned char buff[sizeof(Out)];
combine_as_bits_impl(0, buff, xs...);
Out out;
std::memcpy(&out, buff, sizeof(Out));
return out;
}

用法示例:

auto s = combine_as_bits<std::uint32_t>(
std::uint8_t{0x1}, std::uint8_t{0x2}, std::uint16_t{0x3456});
assert(s == 0x34560201);

Foo(std::uint8_t b0, std::uint8_t b1, std::uint16_t b23) : 
m_n(combine_as_bits<std::uint32_t>(b0, b1, b23)) {}

如果if constexpr不可用,可以使用简单的重载来终止递归:

constexpr void combine_as_bits_impl(std::size_t, unsigned char*) {}
template<typename T, typename... Ts>
constexpr void combine_as_bits_impl(std::size_t offset, unsigned char* out, 
const T& x, const Ts&... xs) {
std::memcpy(out + offset, &x, sizeof(T));
combine_as_bits_impl(offset + sizeof(T), out, xs...);
}