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

时间:2019-10-30 14:11:04

标签: c++

例如,

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个此类变量时该怎么办(不要问为什么)

3 个答案:

答案 0 :(得分:3)

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

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;
};

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

答案 1 :(得分:3)

我怀疑您需要这种功能:

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

答案 2 :(得分:2)

可能的实现(需要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...);
}