在 C++ 中连接内存块

Posted

技术标签:

【中文标题】在 C++ 中连接内存块【英文标题】:Concatenate memory blocks in C++ 【发布时间】:2020-01-31 12:36:30 【问题描述】:

我制作了 10 个二进制可执行文件片段并保留了它们 在单独的内存块中。我是这样使用setter的。

  void SetCDataStream(u_char* _cDataStream, size_t _sizeData)
    
        cDataStream = new u_char [_sizeData]; 
        memmove(cDataStream,_cDataStream, _sizeData);
    

我正在像这样使用 getter 获取这些块

u_char *GetCDataStream()

    return cDataStream;

并从文件内容的开头到结尾以正确的顺序将其放入向量中

std::vector<u_char*> vecCDataStream;

我想连接向量的每个条目以形成原始文件,并且应该能够执行它。 有更好的方法吗?

【问题讨论】:

你还需要记住每个块的大小,因为我打赌每个“内存块”都可以包含 NUL 字节。 您应该使片段已经是 u_char 的 vectors (有一个向量构造函数,它接受两个指针并使用指针之间的数据初始化向量)。那么concatenate them.就不难了。 std::vector::data() 可用于最终获取大向量中的字节。然后您是否能够真正执行存储在级联向量中的代码是另一回事。我记得有人演示了如何执行存储在 char 数组中的函数,但这并不简单。 其实it doesn't look difficult一旦知道如何将数组放入内存中并具有执行权限,这需要一些系统魔法。 @Botje 我也知道每个块的大小,它也可能包含空字节。 哦,如果你已经使用了向量块,GetCDataStream() 可以简单地返回向量按值(如果你是现代 C++);带有移动构造函数的现代 C++ 使其高效。无需为原始指针而苦恼。 【参考方案1】:

如果我理解正确,您根本不需要手动内存管理,也不需要保留内存中的原始内存块位置。在这种情况下,您可以使用 std::vector 来存储这些块 - 如果您愿意,可以将它们压缩成一个大块。

例子:

#include <cstddef>
#include <cstdint>
#include <fstream>
#include <iostream>
#include <vector>

// A class to keep a number of blocks
class BlockMaster 
public:
    using block_t = std::vector<uint8_t>;

    explicit BlockMaster(size_t init_size = 0) : blocksinit_size 

    // Add a new block
    void AddDataStream(const uint8_t* begin, const uint8_t* end) 
        blocks.emplace_back(begin, end);
    

    size_t size() const noexcept  return blocks.size(); 

    // random access to the stored blocks
    block_t& operator[](size_t block_number) noexcept 
        return blocks[block_number];
    
    const block_t& operator[](size_t block_number) const noexcept 
        return blocks[block_number];
    

    // support for iterating over the stored blocks
    auto cbegin() const noexcept  return blocks.cbegin(); 
    auto cend() const noexcept  return blocks.cend(); 
    auto begin() const noexcept  return cbegin(); 
    auto end() const noexcept  return cend(); 
    auto begin() noexcept  return blocks.begin(); 
    auto end() noexcept  return blocks.end(); 

    // create a BlockMaster with one huge block from the stored blocks
    BlockMaster GetSquashedBlocks() 
        BlockMaster result(1);
        for(const block_t& block : *this) 
            result[0].insert(result[0].end(), block.begin(), block.end());
        
        return result;
    

private:
    std::vector<block_t> blocks;
;

// stream all the stored blocks to a file (as if they were one big block, so
// you don't need to squash them for this)
std::ofstream& operator<<(std::ofstream& ofs, const BlockMaster& bm) 
    for(const auto& block : bm)
        ofs.write(reinterpret_cast<const char*>(block.data()),
                  static_cast<std::streamsize>(block.size()));
    return ofs;


int main() 
    unsigned char memory[]1, 2, 3, 4, 5, 6, 7, 8, 9;

    BlockMaster bm;
    bm.AddDataStream(memory + 0, memory + 3);
    bm.AddDataStream(memory + 4, memory + 8);

    std::cout << bm.size() << "\n--\n";

    for(const auto& block : bm) 
        std::cout << ' ' << block.size() << '\n';
    

    bm = bm.GetSquashedBlocks();

    std::cout << "--\n";

    std::cout << bm.size() << "\n--\n";
    for(const auto& block : bm) 
        std::cout << ' ' << block.size() << '\n';
    

输出:

2    // blockmasters number of stored blocks
--
 3   // first blocks size
 4   // second blocks size
--
1    // blockmasters number of stored blocks after squashing
--
 7   // size of the one block after squashing

【讨论】:

【参考方案2】:

假设每个Block 都有一个GetSize() 成员和一个GetCDataStream() 成员,您可以简单地创建一个std::ofstream 对象并使用std::ofstream::write 方法编写每个块:

std::ofstream out("test.bin", std::ios::binary | std::ios::out);
for (Block& b : blocks) 
    out.write(b.GetCDataStream(), b.GetSize());

out.close();

请注意,所有块的串联是否是适用于您平台的有效可执行文件取决于您(Windows 上的 PE、Linux 上的 ELF、macOS 上的 Mach-O)。

【讨论】:

谢谢。它在 Linux 上的 ELF。但我想首先将所有块组装在单个内存块中并将字节转储到文件中。你有什么建议吗?

以上是关于在 C++ 中连接内存块的主要内容,如果未能解决你的问题,请参考以下文章

内存管理c++

Visual Studio 2010 C++:获取 malloc 分配的内存块大小

C++ 遍历进程内存块

c++ 使用数组减少内存

c++基础——动态内存

C++内存泄露及常见情况总结