使用 std::vector<unsigned char> 的内容初始化结构

Posted

技术标签:

【中文标题】使用 std::vector<unsigned char> 的内容初始化结构【英文标题】:Initializing a struct with the contents of a std::vector<unsigned char> 【发布时间】:2014-06-28 20:02:43 【问题描述】:

这似乎应该简单明了,但 Google 很少出现。

什么是初始化简单文件头结构的干净、现代 (C++11) 方法,如下所示

typedef struct FooHeader 
    uint8_t    FooCount;
    uint8_t    BarCount;
    uint32_t   BazOffsets[4];
 FooHeader;

std::vector&lt;unsigned char&gt; 中包含的数据?创建子向量并将其数据转换为标头结构类型是个好主意吗?

【问题讨论】:

您是否假设您的使用可以安全地忽略潜在的平台字节顺序和结构打包问题,并简单地假设所有读者作者对两者共享相同的概念?老实说,这就是让这种活动变得乏味的原因。 是的,因为文件格式已经很成熟,并且到目前为止所有使用它的应用程序都已经就应该如何读取和写入达成一致。该软件也极不可能在 x86 以外的任何平台上使用。 您要创建子向量的目的是什么?另外,您的程序中是否有一个 FooHeader 变量,或者您想使用 std::vector 填充的 std::vector 如果我不必创建子向量,我不会。只是一个想法。在这种情况下,FooHeader 将是一个局部变量。 FooHeader h = *(reinterpret_cast&lt;FooHeader*&gt;(&amp;data_vec[0])) 怎么样? 【参考方案1】:

为避免遇到打包、对齐和字节序问题,最好在字节级别读取数据(在几乎所有现代硬件上,您可以假设 8 位字节,但打包经常在编译器之间更改(甚至只是在不同的编译标志之间),大端和小端计算机仍然很常见)。

这意味着你最好的选择是这样的:

FooHeader load_FooHeader(std::vector<unsigned char> const &dat) 
    static_assert(
        std::numeric_limits<unsigned char>::digits == 8,
        "Assumes 8-bit bytes");

    FooHeader retv;

    retv.FooCount = dat[0];
    retv.BarCount = dat[1];

    //Start at the fifth byte, to allow for padding.
    //If you want to use a packed format, use index = 2;
    std::size_t index4;
    for (std::size_t i0, iend4; i < iend; ++i) 
        retv.BarOffsets[i] = 0;
        //Adjust ordering depending on desired endianness.
        //Currently uses little endian.
        for (std::size_t j0, jend4; j < jend; ++j) 
            retv.BarOffsets[i] |= dat[index + i*4 + (3-j)] << (j*8);
        
    

    return retv;

【讨论】:

以上是关于使用 std::vector<unsigned char> 的内容初始化结构的主要内容,如果未能解决你的问题,请参考以下文章

如何将 unsigned char[] 转换为 std::vector<unsigned char>

Swig:将 std::vector<unsigned char> 传递给从 c++ 生成的 c# 函数

为什么c ++用零来初始化std :: vector,而不是std :: array?

逐个保存unsigned char矢量

在c ++中对向量的向量进行排序

将二进制文件读取到“unsigned char”向量时的模板参数是啥