春眠 發表於 2025-12-3 11:13:10

详解C++ 存储二进制数据容器的几种方法

<div id="navCategory"><h5 class="catalogue">目录</h5><ul class="first_class_ul"><li>1.std::vector&lt;uint8_t&gt;(最常用)</li><ul class="second_class_ul"><li>特点:</li><li>适用场景:</li><li>示例:</li></ul><li>2.std::array&lt;uint8_t, N&gt;(固定大小二进制数据)</li><ul class="second_class_ul"><li>特点:</li><li>适用场景:</li><li>示例:</li></ul><li>3.std::string(兼容字符串操作的二进制数据)</li><ul class="second_class_ul"><li>特点:</li><li>适用场景:</li><li>示例:</li></ul><li>4.std::bitset&lt;N&gt;(固定大小比特序列)</li><ul class="second_class_ul"><li>特点:</li><li>适用场景:</li><li>示例:</li></ul><li>5.std::vector&lt;bool&gt;(动态比特序列)</li><ul class="second_class_ul"><li>特点:</li><li>适用场景:</li><li>示例:</li></ul><li>总结</li><ul class="second_class_ul"></ul></ul></div><p class="maodian"></p><h2>1.std::vector&lt;uint8_t&gt;(最常用)</h2>
<p><code>std::vector</code> 是动态数组容器,搭配 <code>uint8_t</code>(无符号8位整数,即1字节)是存储二进制数据的<strong>首选方案</strong>,尤其适合长度不确定的二进制流(如文件内容、网络数据包)。</p>
<p class="maodian"></p><p class="maodian"></p><p class="maodian"></p><p class="maodian"></p><p class="maodian"></p><h3>特点:</h3>
<ul><li><strong>动态大小</strong>:可随数据量自动扩容,支持 <code>push_back</code>、<code>resize</code> 等操作,灵活处理变长二进制数据。</li><li><strong>连续内存</strong>:元素在内存中连续存储,可通过 <code>data()</code> 方法获取原始字节指针(<code>uint8_t*</code>),方便与 C 风格接口(如系统调用、网络函数)交互。</li><li><strong>C++11 增强</strong>:支持移动语义(<code>std::move</code>),避免大二进制数据的拷贝开销;支持初始化列表(<code>{0x01, 0x02, 0x03}</code>)快速初始化。</li></ul>
<p class="maodian"></p><p class="maodian"></p><p class="maodian"></p><p class="maodian"></p><p class="maodian"></p><h3>适用场景:</h3>
<ul><li>读取文件二进制内容(如图片、音频)。</li><li>网络通信中的缓冲区(发送/接收字节流)。</li><li>动态生成的二进制数据(如加密后的字节序列)。</li></ul>
<p class="maodian"></p><p class="maodian"></p><p class="maodian"></p><p class="maodian"></p><p class="maodian"></p><h3>示例:</h3>
<div class="jb51code"><pre class="brush:cpp;">#include &lt;vector&gt;
#include &lt;cstdint&gt;// 包含uint8_t

int main() {
    // 存储二进制数据(例如一个简单的协议包)
    std::vector&lt;uint8_t&gt; binary_data = {0x01, 0x02, 0xFF, 0x00};
   
    // 动态添加数据
    binary_data.push_back(0x03);
   
    // 获取原始字节指针,用于C风格接口
    uint8_t* raw_ptr = binary_data.data();
    size_t size = binary_data.size();// 字节数:5
    return 0;
}
</pre></div>
<p class="maodian"></p><h2>2.std::array&lt;uint8_t, N&gt;(固定大小二进制数据)</h2>
<p><code>std::array</code> 是 C++11 新增的固定大小数组容器,适合存储<strong>长度已知且固定</strong>的二进制数据(如协议头、固定大小的校验码)。</p>
<h3>特点:</h3>
<ul><li><strong>编译期固定大小</strong>:声明时需指定长度(如 <code>std::array&lt;uint8_t, 16&gt;</code> 表示16字节),内存分配在栈上(或静态区),无需动态内存管理。</li><li><strong>连续内存</strong>:同 <code>vector</code>,支持 <code>data()</code> 获取原始指针,性能优于动态数组。</li><li><strong>无额外开销</strong>:相比 <code>vector</code> 没有动态扩容的额外内存(如容量管理的指针),空间效率更高。</li></ul>
<h3>适用场景:</h3>
<ul><li>固定格式的二进制协议头(如16字节的TCP头部部分字段)。</li><li>哈希值、UUID等固定长度的二进制数据(如16字节的MD5结果)。</li><li>嵌入式系统中对内存分配有严格限制的场景。</li></ul>
<h3>示例:</h3>
<div class="jb51code"><pre class="brush:cpp;">#include &lt;array&gt;
#include &lt;cstdint&gt;

int main() {
    // 存储16字节的固定二进制数据(如UUID)
    std::array&lt;uint8_t, 16&gt; uuid = {
      0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77,
      0x88, 0x99, 0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF
    };
   
    // 访问单个字节
    uint8_t first_byte = uuid;// 0x00
    return 0;
}
</pre></div>
<p class="maodian"></p><h2>3.std::string(兼容字符串操作的二进制数据)</h2>
<p><code>std::string</code> 本质是&ldquo;字节序列容器&rdquo;(C++标准未限制必须是字符串),可存储包含空字符(<code>\0</code>)的二进制数据,适合需要同时支持字符串操作和二进制存储的场景。</p>
<h3>特点:</h3>
<ul><li><strong>兼容字符串API</strong>:可使用 <code>substr</code>、<code>find</code> 等方法处理二进制数据中的片段,方便解析包含文本标识的二进制流(如HTTP协议中的二进制附件)。</li><li><strong>连续内存</strong>:支持 <code>data()</code> 或 <code>c_str()</code> 获取字节指针(注意 <code>c_str()</code> 会在末尾附加 <code>\0</code>,但 <code>data()</code> 在C++11中与 <code>c_str()</code> 等效,需谨慎处理)。</li><li><strong>注意事项</strong>:二进制数据中的 <code>\0</code> 不会被视为&ldquo;结束符&rdquo;,<code>size()</code> 方法会返回真实字节数(包含 <code>\0</code>)。</li></ul>
<h3>适用场景:</h3>
<ul><li>存储包含文本和二进制混合的数据(如邮件中的MIME附件)。</li><li>需要对二进制数据进行子串查找、拼接等操作的场景。</li></ul>
<h3>示例:</h3>
<div class="jb51code"><pre class="brush:cpp;">#include &lt;string&gt;
#include &lt;cstdint&gt;

int main() {
    // 存储包含空字符的二进制数据
    std::string binary_str;
    binary_str += static_cast&lt;char&gt;(0x01);
    binary_str += static_cast&lt;char&gt;(0x00);// 空字符,仍会被计入长度
    binary_str += static_cast&lt;char&gt;(0x02);
   
    std::cout &lt;&lt; "长度:" &lt;&lt; binary_str.size();// 输出3(包含空字符)
    return 0;
}
</pre></div>
<p class="maodian"></p><h2>4.std::bitset&lt;N&gt;(固定大小比特序列)</h2>
<p><code>std::bitset</code> 用于存储<strong>固定长度的比特(bit)序列</strong>(而非字节),适合需要精确控制每一个比特的场景(如标志位、压缩存储布尔值)。</p>
<h3>特点:</h3>
<ul><li><strong>比特级操作</strong>:支持单个比特的设置(<code>set</code>)、清空(<code>reset</code>)、翻转(<code>flip</code>),以及批量逻辑运算(与、或、异或)。</li><li><strong>编译期固定大小</strong>:长度 <code>N</code> 必须是编译期常量(如 <code>std::bitset&lt;32&gt;</code> 表示32个比特)。</li><li><strong>空间高效</strong>:每个比特仅占1/8字节,比 <code>vector&lt;bool&gt;</code> 更高效(无额外指针开销)。</li></ul>
<h3>适用场景:</h3>
<ul><li>存储大量布尔标志(如32个状态标志仅需4字节)。</li><li>协议中的比特位字段(如TCP头部的控制位:SYN、ACK等)。</li><li>比特级算法(如位掩码、压缩算法)。</li></ul>
<h3>示例:</h3>
<div class="jb51code"><pre class="brush:cpp;">#include &lt;bitset&gt;

int main() {
    // 32位比特序列,存储标志位
    std::bitset&lt;32&gt; flags;
   
    // 设置第0位和第2位(从0开始)
    flags.set(0);
    flags.set(2);
   
    // 检查第0位是否为1
    bool is_set = flags.test(0);// true
   
    // 整体转换为整数(获取比特序列的数值)
    uint32_t value = flags.to_ulong();// 二进制101 → 十进制5
    return 0;
}
</pre></div>
<p class="maodian"></p><h2>5.std::vector&lt;bool&gt;(动态比特序列)</h2>
<p><code>std::vector&lt;bool&gt;</code> 是 <code>vector</code> 的特化版本,用于存储<strong>动态长度的比特序列</strong>,本质是&ldquo;比特容器&rdquo;(每个元素占1比特)。</p>
<h3>特点:</h3>
<ul><li><strong>动态大小</strong>:长度可在运行时调整(如 <code>push_back</code> 添加比特),适合比特数不确定的场景。</li><li><strong>空间优化</strong>:比 <code>vector&lt;uint8_t&gt;</code> 节省空间(存储1000个布尔值仅需约125字节)。</li><li><strong>注意事项</strong>:迭代器行为特殊(返回代理对象而非直接引用),部分操作效率可能低于 <code>std::bitset</code> 或 <code>vector&lt;uint8_t&gt;</code>。</li></ul>
<h3>适用场景:</h3>
<ul><li>动态生成的比特流(如编码算法输出的可变长度比特序列)。</li><li>存储数量不确定的布尔状态(如动态筛选结果的标志)。</li></ul>
<h3>示例:</h3>
<div class="jb51code"><pre class="brush:cpp;">#include &lt;vector&gt;

int main() {
    // 动态比特序列
    std::vector&lt;bool&gt; bits;
   
    // 添加比特
    bits.push_back(true);   // 第0位:1
    bits.push_back(false);// 第1位:0
    bits.push_back(true);   // 第2位:1
   
    // 访问第2位
    bool bit2 = bits;// true
    return 0;
}
</pre></div>
<p class="maodian"></p><h2>总结</h2>
<p>C++ 中存储二进制数据的核心选择及适用场景:</p>
<table><thead><tr><th>数据结构</th><th>存储单位</th><th>大小特性</th><th>核心优势</th><th>适用场景</th></tr></thead><tbody><tr><td>std::vector&lt;uint8_t&gt;</td><td>字节</td><td>动态大小</td><td>灵活、连续内存、适合变长数据</td><td>网络缓冲区、文件内容、动态字节流</td></tr><tr><td>std::array&lt;uint8_t, N&gt;</td><td>字节</td><td>固定大小(编译期)</td><td>无动态开销、栈上分配</td><td>协议头、固定长度哈希/UUID</td></tr><tr><td>std::string</td><td>字节</td><td>动态大小</td><td>兼容字符串操作,支持混合数据</td><td>文本+二进制混合数据、带标识的字节流</td></tr><tr><td>std::bitset&lt;N&gt;</td><td>比特</td><td>固定大小(编译期)</td><td>高效比特操作、空间紧凑</td><td>标志位、固定长度比特字段</td></tr><tr><td>std::vector&lt;bool&gt;</td><td>比特</td><td>动态大小</td><td>动态调整比特数,空间优化</td><td>变长比特流、动态布尔状态集合</td></tr></tbody></table>
<p>根据需求选择:动态字节流优先用 <code>vector&lt;uint8_t&gt;</code>,固定字节用 <code>array</code>,比特级操作选 <code>bitset</code> 或 <code>vector&lt;bool&gt;</code>,混合文本和二进制用 <code>std::string</code>。</p>
<p>到此这篇关于详解C++ 存储二进制数据容器的几种方法的文章就介绍到这了,更多相关C++ 存储二进制内容请搜索琼殿技术社区以前的文章或继续浏览下面的相关文章希望大家以后多多支持琼殿技术社区!</p>
                           
                            <div class="art_xg">
                              <b>您可能感兴趣的文章:</b><ul><li>C++中几种将整数转换成二进制输出的方法总结</li><li>C++实现string存取二进制数据的方法</li><li>C++ 十进制转换为二进制的实例代码</li><li>C++实现读入二进制数并转换为十进制输出</li><li>详解C++编程中对二进制文件的读写操作</li><li>C++实现十进制数转换为二进制数的数学算法</li><li>c++ 一个二进制串转化为整数的解决方法</li><li>C++二进制翻转实例分析</li><li>C++如何计算二进制数中1的个数</li></ul>
                            </div>

                        </div>
                        <!--endmain-->
頁: [1]
查看完整版本: 详解C++ 存储二进制数据容器的几种方法