fwrite等写文件的函数都是void*的输入,直接填入结构体的指针即可,前提是结构体中不能有指针类型,有的话那些东西写不进去.
可以这样理解,结构体内全部存储的是成员变量,结构体首地址存储的是第一个变量的首地址,结束位置存储的是最后一个变量的位置。
如果用同一种编译器,对变量的地址分布采取的策略的相同的,包括内存对齐,包括大端小端等问题。故而这样操作是没有问题的。
但是C++类不可以,有函数,有虚函数表。
结构体写入文件后打开有乱码,是因为内存对齐的原因,增加的那部分内存。
例如如下的结构体:
struct st
{
char a; //内存偏移量0 内存中byte[0]存储 A
char b;//内存偏移量 1 内存byte[1] 存储 B
char e;//内存偏移量 2 内存byte[2] 存储 C
int d; //这个就有点问题了,他有内存对齐了,偏移量回事 4 故而中间一个byte填充 0 打印没打印出来。
char* p;//注意是个32为地址偏移量应该是8 内存对齐。 中间打印的是0 最后打印的是地址,故而乱码
}; 总体占用12个字节
int main()
{
st s;
s.a = 'A';
s.b = 'B';
s.d = 'C';
s.e = 'D';
s.p = "hello,word";
FILE* pFile = fopen("G:\\st.txt","wb");
if(pFile == NULL) cout<<"error"<<endl;
fwrite(&s,sizeof(s),1,pFile);
fclose(pFile);
system("pause");
return 0;
}
打印的应该是 ABD C ?@
下面是CLass 类型的
#include<iostream>
#include<stdio.h>
using namespace std;
class Cst
{
private:
int a;
int b;
public:
Cst(int a,int b):a(a),b(b) { }
Cst() { }
virtual void Print() {cout<<"first virual"<<endl;}
virtual void print() { cout<<a<<b<<endl;}
char* name;
};
int main()
{
FILE* pFile;
pFile = fopen("G:\\st.txt","r");
Cst ss(100,200);
fread(&ss,sizeof(ss),1,pFile);
fclose(pFile);
ss.print();
cout<<ss.name<<endl;
system("pause");
return 0;
}
除了 name 无法读取,之外。因为name 没有存储到文件中,类定义中也没有,因此不可能知道。指针找不到地方。
其他的都没问题。
回忆下对象在内存中的分布情况
1 虚表 指针 ---------->指向的是类中具体函数的地址。
下来是继承变量
自己变量
注意函数指针并没有存在对象中,而是对象在调研函数时候会在类中代码,也就是代码区寻找。
深入理解下,你会问到函数也是指针,虚表也有指针,为什么这些指针能找到想要的地址。
我的回答是,非虚函数首先没有在对象中存储指针信息,运行时候,对象会找到相应的类。然后根据函数名(也就是地址,偏移量)找到函数入口
虚函数的虚表不就是对象的首地址,偏移量不就是0嘛。 因此可以找得到虚表。
一定要理解,函数虚表,和函数列表在代码区的类中存储。不能修改。对于虚函数,多了一个指向他的指针罢了
综上所诉,利用类或者结构体直接写入文件存储,持续化,效果很差,移植性,兼容性很差,受到编译器,运行环境的影响。 而切两边定义的类型要完全一致