【发布时间】:2020-04-12 12:11:40
【问题描述】:
在处理遗留的C 代码时,我需要读取和复制 C 样式结构的内存位置。
给定一个指向结构的指针,我应该更好地使用 C 风格 std::memcpy 还是 C++ std::copy_n?或者它们是等价的?
有一个具体的,虽然微不足道的例子:
#include <cstring>
#include <algorithm>
struct Ctype {
double x;
int a;
};
int main()
{
Ctype a{1, 2};
auto p = &a;
auto buffer = reinterpret_cast<decltype(p)>(::operator new(sizeof(a)));
// Are the two following equivalent and both well-defined?
std::memcpy(buffer, p, sizeof(a));
std::copy_n(p, 1, buffer);
Ctype b{3, 4};
// Are the two following equivalent and both well-defined?
std::memcpy(&b, buffer, sizeof(b));
std::copy_n(buffer, 1, &b);
delete buffer;
return 0;
}
问题出现在序列化 C 结构的上下文中。在具体情况下,我不知道在 C 库中定义的 Ctype 的内容。
一些说明
该示例可能过于简化,显然可以简单地使用b=*buffer。然而,我想到的是buffer 可以从外部提供,例如它可以是从磁盘读取的数据序列。然后我需要主动将缓冲区复制到b中。
加法
这是一个更接近我的想法的例子。它使用zlib 库从磁盘写入/读取:zlib 函数gzread 和gzwrite 接受void * 指向要读取/写入的内存缓冲区的指针。
#include <cstring>
#include <algorithm>
#include <fstream>
extern "C" {
#include <zlib.h>
}
struct Ctype {
double x;
int a;
};
int main()
{
Ctype a{1, 2};
auto p = &a;
auto buffer = ::operator new(sizeof(a));
// Are the two following equivalent and both well-defined?
std::memcpy(buffer, p, sizeof(a));
std::copy_n(p, 1, static_cast<Ctype *>(buffer));
// Saving the files
gzFile f = gzopen("conf.dat", "w");
gzwrite(f, buffer, sizeof(a));
gzclose(f);
Ctype b{3, 4};
// Reading file
f = gzopen("conf.dat", "r");
gzread(f, buffer, sizeof(a));
gzclose(f);
// Are the two following equivalent and both well-defined?
std::memcpy(&b, buffer, sizeof(b));
std::copy_n(static_cast<Ctype *>(buffer), 1, &b);
operator delete(buffer);
return 0;
}
【问题讨论】:
-
为什么不只是
*buffer = b;?由于它是 C 风格的结构,因此您不必担心构造函数或析构函数。 -
不知道
Ctype的内容是什么意思?你的意思是它可能不是 double+int 或者你不知道它们的值? -
@Barmar 我想到了从 outside 给定缓冲区的情况,并且您想通过显式复制内存内容来使用缓冲区初始化 b。
-
@ALX23z 我不知道它是 int、double 还是别的什么。我所知道的是,如果我包含 C 库,我就有这种类型的 Ctype,它是一个 C 结构。当然,我可以检查 C 代码,但这违背了将 C 库用作“用户”的想法。
-
@francesco 如果您可以使用
sizeof(b),您必须有权访问结构定义。
标签: c++ c memory-management