在 C++ 中连接内存块
Concatenate memory blocks in C++
我制作了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;
}
并从文件内容的开头到结尾按照正确的顺序放入vector中
std::vector<u_char*> vecCDataStream;
我想连接矢量的每个条目以形成原始文件并且应该能够执行它。
有更好的方法吗?
假设每个 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();
请注意,所有块的串联是否为您平台的有效可执行文件(PE 在 Windows,ELF 在 Linux,Mach-O 在 macOS)。
如果我没理解错的话,你根本不需要手动管理内存,也不需要在内存中保留原来的内存块位置。在这种情况下,您可以使用 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) : blocks{init_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
我制作了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;
}
并从文件内容的开头到结尾按照正确的顺序放入vector中
std::vector<u_char*> vecCDataStream;
我想连接矢量的每个条目以形成原始文件并且应该能够执行它。 有更好的方法吗?
假设每个 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();
请注意,所有块的串联是否为您平台的有效可执行文件(PE 在 Windows,ELF 在 Linux,Mach-O 在 macOS)。
如果我没理解错的话,你根本不需要手动管理内存,也不需要在内存中保留原来的内存块位置。在这种情况下,您可以使用 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) : blocks{init_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