将结构和类写入磁盘

Posted

技术标签:

【中文标题】将结构和类写入磁盘【英文标题】:writing structs and classes to disk 【发布时间】:2010-05-22 18:08:12 【问题描述】:

以下函数将结构写入文件。

#define PAGESIZE  sizeof(BTPAGE)
#define HEADERSIZE 2L

    int btwrite(short rrn, BTPAGE *page_ptr)
    
        long addr;
        addr = (long) rrn * (long) PAGESIZE + HEADERSIZE;
        lseek(btfd, addr, 0);
        return (write(btfd, page_ptr, PAGESIZE));
    

下面是结构体

typedef struct 
    short keycount;             /* number of keys in page   */
    int  key[MAXKEYS];              /* the actual keys      */
    int  value[MAXKEYS];            /* the actual values        */
    short child[MAXKEYS+1];     /* ptrs to rrns of descendants  */
 BTPAGE;

如果我将结构更改为类会发生什么,它仍然可以正常工作吗?

如果我添加类函数,它在磁盘上占用的大小会增加吗?

【问题讨论】:

【参考方案1】:

你需要在这里学习很多东西。

首先,您将结构视为字节数组。由于strict aliasing rule,这是严格未定义的行为。任何事情都有可能发生。所以不要这样做。请改用正确的序列化(例如通过boost)。是的,这很乏味。是的,这是必要的。 即使您忽略了不确定性,并选择依赖于某些特定的编译器实现(即使在下一个编译器版本中也可能发生变化),仍然有理由不这样做。 如果你在一台机器上保存一个文件,然后在另一台机器上加载它,你可能会得到垃圾,因为第二台机器使用不同的浮点表示,或者不同的endianness,或者有不同的alignment rules,等等。 如果您的结构包含任何指针,很有可能将它们逐字保存然后再加载它们会导致地址不指向任何有意义的位置。 通常,当您添加成员函数时,会发生这种情况: 函数的机器代码存储在所有类实例共享的位置(复制它是没有意义的,因为它在逻辑上是不可变的) 一个隐藏的“this”指针在被调用时被传递给函数,因此它知道它被调用的是哪个对象。 这些都不需要实例中的任何存储空间。 但是,当您添加至少 一个 虚函数时,编译器通常还需要添加一个名为 vtable 的数据块(请仔细阅读)。这使得可以根据对象的当前运行时类型(也称为多态性)调用不同的代码。因此,您添加到类的第一个虚函数可能确实增加了对象大小。

【讨论】:

关于严格别名,允许将任何 POD 类型的对象视为字节数组。任何类型的对象都可以通过char* 访问,并且将构成 POD 类型对象的字节复制到 char 数组中,然后将这些字节复制回相同 POD 类型的对象中是明确定义的。 (当然,您关于不可移植性的观点仍然有效)。【参考方案2】:

在 C++ 中,structclass 之间的区别仅在于结构的成员和基类默认情况下是公共的,而对于类而言,它们默认情况下是私有的。

仅当结构是plain old data, or POD, type 时,将结构的字节简单地写入文件然后再次读回它们的技术才有效。如果您修改结构使其不再是 POD,则不能保证此技术有效(描述 POD 结构的规则在链接问题的答案中列出)。

【讨论】:

【参考方案3】:

如果这个类有任何虚函数,那么你就有麻烦了;如果没有虚函数,你应该仍然可以(当然,这同样适用于结构,因为它也可以有虚函数:结构和类之间的区别只是结构中的默认可见性是公共的,在类中这是私人的)。

【讨论】:

【参考方案4】:

如果您正在对类进行更多序列化,请考虑使用 google 协议缓冲区或类似的东西 see this question

【讨论】:

以上是关于将结构和类写入磁盘的主要内容,如果未能解决你的问题,请参考以下文章

vhd怎么写入数据

为啥用C#在磁盘上写入文件后内存没有释放

LevelDB的源码阅读 Compaction操作

用 C++ 将 OpenCV 帧写入磁盘:单线程写入速度是不是受磁盘吞吐量以外的任何限制?

sync---强制将被改变的内容立刻写入磁盘

使用 boost-asio 时实时将缓冲区写入磁盘