在结构体内部将数组切换为向量,如何处理文件io字节对齐

发布于 2025-01-17 06:21:06 字数 1584 浏览 2 评论 0原文

我们曾经有一个结构:

const int NUMBER_OF_ELEMENTS = 10;  
struct myStruct1
{
    uint32_t var1;
    uint64_t var2;
    uint32_t elements[NUMBER_OF_ELEMENTS];
};

但是,展望未来,我们希望元素的数量是可变的。我想我最好这样做:

struct myStruct2
{
    uint32_t var1;
    uint64_t var2;
    std::vector<uint32_t> elements;
    myStruct2(int len){ elements.resize(len);};
};

对于从文件读取/写入,我们过去只是这样做:

myStruct1 ms1;
std::ofstream outfile(FILENAME,std::ofstream::out | std::ofstream::binary);
outfile.write((const char*)&ms1,sizeof(myStruct1));
outfile.close();

myStruct1 msread1;
std::ifstream infile(FILENAME, std::ifstream::in | std::ifstream::binary);
infile.read((char *)&msread1, sizeof(myStruct1));
infile.close();

显然我不能再为矢量版本这样做了。所以,我必须逐个元素地阅读。

myStruct2 msread2(NUMBER_OF_ELEMENTS);
std::ifstream infile(FILENAME, std::ifstream::in | std::ifstream::binary);
infile.read((char *)&msread2.var1, sizeof(uint32_t));
infile.read((char *)&msread2.var2, sizeof(uint64_t));
for (int i=0; i<NUMBER_OF_ELEMENTS; i++)
{
    infile.read((char *)&msread2.elements[i], sizeof(uint32_t));
}
infile.close();

然而,这会遇到字节对齐的问题...结构体(以及文件中)的 var1 之后有 4 个字节的填充。先读取 var1,然后读取 var2 不会跳过此 pad。

我可以使用 #pragma pack(1) 进行写作和阅读。不过,我希望读者能够与使用填充创建的旧文件兼容。

读取 var1 后,我可以手动查找 4 个字节(或读取虚拟 4 字节变量)。但我觉得可能有更好的方法。

我可以将 var1 和 var2 放在 myStruct1 或 myStruct2 中它们自己的结构中,然后一起读取它们,也许这对于 io 来说更干净一些,但访问它们会需要一个额外的步骤,例如 ms1.headvars.var1 而不仅仅是 ms1.var1。 (整个代码库中有更多更改)

有关更好的解决方案的建议吗?

We used to have a structure:

const int NUMBER_OF_ELEMENTS = 10;  
struct myStruct1
{
    uint32_t var1;
    uint64_t var2;
    uint32_t elements[NUMBER_OF_ELEMENTS];
};

However, going forward we want the number of elements to be variable. I think I would best do this as:

struct myStruct2
{
    uint32_t var1;
    uint64_t var2;
    std::vector<uint32_t> elements;
    myStruct2(int len){ elements.resize(len);};
};

For reading/writing from a file, we used to simply do:

myStruct1 ms1;
std::ofstream outfile(FILENAME,std::ofstream::out | std::ofstream::binary);
outfile.write((const char*)&ms1,sizeof(myStruct1));
outfile.close();

myStruct1 msread1;
std::ifstream infile(FILENAME, std::ifstream::in | std::ifstream::binary);
infile.read((char *)&msread1, sizeof(myStruct1));
infile.close();

Obviously I can't do that anymore for the vector version. So, I would have to read element by element.

myStruct2 msread2(NUMBER_OF_ELEMENTS);
std::ifstream infile(FILENAME, std::ifstream::in | std::ifstream::binary);
infile.read((char *)&msread2.var1, sizeof(uint32_t));
infile.read((char *)&msread2.var2, sizeof(uint64_t));
for (int i=0; i<NUMBER_OF_ELEMENTS; i++)
{
    infile.read((char *)&msread2.elements[i], sizeof(uint32_t));
}
infile.close();

However, this runs into the problem of byte alignment... there is 4 bytes of padding after var1 in the struct (and in the file). Reading var1 then var2 doesn't skip this pad.

I could use #pragma pack(1) both for writing and for reading. However I would like the reader to be compatible with old files which were created with the padding.

I could manually have a seek of 4 bytes (or read a dummy 4 byte variable) after reading var1. But I feel there's probably better ways.

I could put var1 and var2 in their own struct within myStruct1 or myStruct2, and read them together, maybe this is a bit cleaner for io but then accessing them would have an extra step eg ms1.headvars.var1 instead of just ms1.var1. (more changes throughout the codebase)

Any recommendations on a nicer solution?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

dawn曙光 2025-01-24 06:21:06

您不能简单地将矢量二进制文件写入磁盘;它在内部包含已使用的大小以及指向动态分配的实际数据的指针(以及编译器制造商喜欢放在那里的任何其他内容;以任何顺序)。您最多只能得到写入文件的指针值。

相反,您需要编写大小,然后分两步编写其内容:v.size()v.data()
读回它们时,首先读取大小,准备一个向量,然后读回数据:v.resize(size);,然后读入v.data() [是的,你可以写入v.data()!]

You cannot simply write a vector binary to disk; it contains internally the size, used, and a pointer to the real data which is dynamically allocated (and whatever else the compiler-maker enjoyed to put there; in any sequence). You would get at best the pointer value written into your file.

Instead, you need to write the size, and then its content in two steps: v.size(), and v.data().
When reading them back, you read first the size, prepare a vector, and then read the data back: v.resize(size);, then read into v.data() [yes, you can write into v.data()!]

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文