简体   繁体   English

C++ uint8_t 向量到 uint32_t 向量

[英]C++ vector of uint8_t to vector of uint32_t

std::vector<uint8_t> vector1 = { 1, 2, 3, 4 };

I would like to transform the vector above in its uint32_t version.我想将上面的向量转换为 uint32_t 版本。 I tried doing:我试着做:

std::vector<uint32_t> vector2(vector1.begin(), vector2.end());

but this code returns the same array in 32 bit version, so the content is still { 1, 2, 3, 4 }.但是这段代码在 32 位版本中返回相同的数组,所以内容仍然是 { 1, 2, 3, 4 }。

What I expect to get is an array of a single value (in this case) of 0x01020304.我期望得到的是一个包含单个值(在本例中)为 0x01020304 的数组。

Is there any way to achieve that preferably without using for loop?有什么方法可以在不使用 for 循环的情况下实现这一目标?

Thank you.谢谢你。

EDIT:编辑:

My solution, don't know if it's a good practice, but from what I learned about vectors it should be completely valid:我的解决方案,不知道这是否是一个好习惯,但从我对向量的了解来看,它应该是完全有效的:

std::vector<uint32_t> vector2((uint32_t*)vector1.data(), (uint32_t*)(vector1.data() + vector1.size()*sizeof(uint8_t)));

I recommend using a loop to do this for simplicity为简单起见,我建议使用循环来执行此操作

#include <cstdint>
#include <exception>
#include <vector>

std::uint32_t 
combine(std::uint8_t a, 
        std::uint8_t b, 
        std::uint8_t c, 
        std::uint8_t d)
{
    return (std::uint32_t(a) << 24) | 
           (std::uint32_t(b) << 16) | 
           (std::uint32_t(c) << 8) | 
            std::uint32_t(d);
}

std::vector<std::uint32_t> 
combine_vector(const std::vector<std::uint8_t>& items)
{
    if (items.size() % 4 != 0)
        throw std::exception();

    std::vector<std::uint32_t> ret;
    ret.reserve(items.size() / 4);
    for (std::size_t i = 0; i < items.size(); i += 4) {
        ret.push_back(
            combine(items[i + 0], 
                    items[i + 1],
                    items[i + 2],
                    items[i + 3]));
    }

    return ret;
}

I suspect you would need to implement a custom iterator type to do this without using a raw loop.我怀疑您需要实现自定义迭代器类型才能在不使用原始循环的情况下执行此操作。

I made such an iterator我做了这样一个迭代器

#include <iterator>

class combine_iterator
{
public:
    using value_type = std::uint32_t;
    using reference = const value_type&;
    using pointer = const value_type*;
    using difference_type = std::ptrdiff_t;
    using iterator_category = std::input_iterator_tag;

    combine_iterator(const std::uint8_t* data, std::size_t count) :
        m_data(data)
    {
        if (count % 4 != 0)
            throw std::exception();

        if (count > 0)
            ++*this;
    }

    reference
    operator*() const
    {
        return m_cur_val;
    }

    pointer
    operator->() const
    {
        return &m_cur_val;
    }

    friend combine_iterator&
    operator++(combine_iterator& rhs)
    {
        std::uint8_t a = *(rhs.m_data++);
        std::uint8_t b = *(rhs.m_data++);
        std::uint8_t c = *(rhs.m_data++);
        std::uint8_t d = *(rhs.m_data++);
        rhs.m_cur_val = combine(a, b, c, d);
        return rhs;
    }

    friend combine_iterator
    operator++(combine_iterator& lhs, int)
    {
        auto cp = lhs;
        ++lhs;
        return cp;
    }

    friend bool
    operator!=(const combine_iterator& lhs, const combine_iterator& rhs)
    {
        return (lhs.m_data != rhs.m_data);
    }

private:
    const std::uint8_t* m_data;
    std::uint32_t m_cur_val;
};

int main()
{
    std::vector<std::uint8_t> data = { 1, 2, 3, 4, 5, 6, 7, 8 };

    std::vector<std::uint32_t> res(
        combine_iterator(data.data(), data.size()),
        combine_iterator(data.data() + data.size(), 0));
}

The iterator contains at least one bug.迭代器至少包含一个错误。 I'm leaving the bugs in as an educational lesson why using a loop if often easier to get correct than implementing custom iterators.我将这些错误作为教育课程留下来,为什么使用循环通常比实现自定义迭代器更容易纠正。 Custom iterators should ideally only be created if we create a container which needs it, or the mental overhead of creating a custom iterator can be justified.理想情况下,仅当我们创建需要它的容器时才应创建自定义迭代器,否则创建自定义迭代器的心理开销是合理的。

You can use ranges, either by using the range-v3 library, or the C++20 std::ranges.您可以通过使用 range-v3 库或 C++20 std::ranges 来使用范围。

std::vector<uint8_t> vector1 = { 1, 2, 3, 4, 5, 6, 7, 8 };

std::vector<uint32_t> vec2 = 
            vector1 
            | view::chunk(4) 
            | views::transform(
                [](auto&& range){
                    return accumulate(
                        range, 
                        static_cast<uint32_t>(0), 
                        [](auto acc, auto i)
                        {
                            return acc << 8 | i;
                        }
                    );
                })
            | to<std::vector>();

vec2 will contain {0x1020304, 0x5060708}. vec2将包含 {0x1020304, 0x5060708}。

See it on godbolt: https://godbolt.org/z/6z6ehfKbq在godbolt上看到它: https://godbolt.org/z/6z6ehfKbq

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM