C語言中將結構體寫入文件


 可以使用fwrite()將一個結構體寫入文件:
  fwrite(&some_struct,sizeof somestruct,1,fp);
對應的fread函數可以再把它讀出來,此處fwrite受到一個結構的指針並把這個結構的內存映像作為字節流寫入文件。sizeof操作符計算出結構占用的字節數。
但是這樣用內存映像寫出的數據文件卻是不能夠移植的,尤其是當結構中包含浮點成員或指針的時候。結構的內存布局跟機器和編譯器都有關。不同的編譯器可能使用不同數量的填充位,不同機器上基本類型的大小和字節順序也不盡相同。因此,作為內存映像寫出的結構在別的機器上(甚至是被別的編譯器編譯之后)不一定能被讀回來。
  同時注意如果結構包含任何指針(char*字符串或指向其他數據結構的指針),則只有指針值會被寫入文件。當它們再次被讀回來的時候可能已經失效。最后為了廣泛的可移植性,你必需用“b”標志打開文件。

讀寫結構體的程序如下:

將結構體寫入文件:

View Code
#include <stdio.h>
#include <stdlib.h>

typedef  struct {
     char c;
     int h;
     short n;
     long m;
     float f;
     double d1;
     char *s;
     double d2;
}st;
int main( void)
{
    FILE *fp;
    st sa,sb;
     char *str= " abcdefg ";
    sa.c= ' K ';
    sa.h=- 3;
    sa.n= 20;
    sa.m= 100000000;
    sa.f= 33.32f;
    sa.d1= 78.572;
    sa.d2= 33.637;
    sa.s=str;
    fp=fopen( " st.txt ", " w+ ");
     if(!fp)
    {
        printf( " errror!\n ");
        exit(- 1);
    }
    printf( " sa:c=%c,h=%d,n=%d,m=%d,f=%f,d1=%f,s=%s,d2=%f\n ",sa.c,sa.h,sa.n,sa.m,sa.f,sa.d1,sa.s,sa.d2);
    printf( " sizeof(sa)=%d:&c=%x,&h=%x,&n=%x,&m=%x,&f=%x,&d1=%x,&s=%x,&d2=%x\n ", sizeof(sa),&sa.c,&sa.h,&sa.n,&sa.m,&sa.f,&sa.d1,&sa.s,&sa.d2);
    fwrite(&sa, sizeof(sa), 1,fp);
    rewind(fp);
    fread(&sb, sizeof(sb), 1,fp);
    printf( " sb:c=%c,h=%d,n=%d,m=%d,f=%f,d1=%f,s=%s,d2=%f\n ",sb.c,sb.h,sb.n,sb.m,sb.f,sb.d1,sb.s,sb.d2);
       
    fclose(fp);
    
     return  0;
}

從文件中讀出結構體:

View Code
#include <stdio.h>
#include <stdlib.h>

typedef  struct {
     char c;
     int h;
     short n;
     long m;
     float f;
     double d1;
     char *s;
     double d2;
}st;
int main( void)
{
    FILE *fp;
    st sb;
    fp=fopen( " st.txt ", " r ");
     if(!fp)
    {
        printf( " errror!\n ");
        exit(- 1);
    }
    fread(&sb, sizeof(sb), 1,fp);
    printf( " sb:c=%c,h=%d,n=%d,m=%d,f=%f,d1=%f,s=%s,d2=%f\n ",sb.c,sb.h,sb.n,sb.m,sb.f,sb.d1,sb.s,sb.d2);
    printf( " sizeof(sb)=%d:&c=%x,&h=%x,&n=%x,&m=%x,&f=%x,&d1=%x,&s=%x,&d2=%x\n ", sizeof(sb),&sb.c,&sb.h,&sb.n,&sb.m,&sb.f,&sb.d1,&sb.s,&sb.d2);
       
    fclose(fp);
    
     return  0;
}

在linux平台下的GCC編譯器進行編譯后的結果如下:

首先是結構體寫入文件:

sa:c=K,h=-3,n=20,m=100000000,f=33.320000,d1=78.572000,s=abcdefg,d2=33.637000
sizeof(sa)=40:&c=bfb98a10,&h=bfb98a14,&n=bfb98a18,&m=bfb98a1c,&f=bfb98a20,&d1=bfb98a24,&s=bfb98a2c,&d2=bfb98a30
sb:c=K,h=-3,n=20,m=100000000,f=33.320000,d1=78.572000,s=abcdefg,d2=33.637000

從文件中讀出結構體:

sb:c=K,h=-3,n=20,m=100000000,f=33.320000,d1=78.572000, s=���o�� ,d2=33.637000
sizeof(sb)=40: &c=bfbc9964,&h=bfbc9968,&n=bfbc996c,&m=bfbc9970,&f=bfbc9974,&d1=bfbc9978,&s=bfbc9980,&d2=bfbc9984

在windows xp 平台下利用Visual C++編譯器編譯后結果如下:

寫入結構體: 

sa:c=K,h=-3,n=20,m=100000000,f=33.320000,d1=78.572000,s=abcdefg,d2=33.637000
sizeof(sa)=48:&c=12ff28,&h=12ff2c,&n=12ff30,&m=12ff34,&f=12ff38,&d1=12ff40,&s=12ff48,&d2=12ff50
sb:c=K,h=-3,n=20,m=100000000,f=33.320000,d1=78.572000,s=abcdefg,d2=33.637000

讀出結構體:

sb:c=K,h=-3,n=20,m=100000000,f=33.320000,d1=78.572000,s=e,d2=33.637000

sizeof(sb)=48 :&c=12ff28,&h=12ff2c,&n=12ff30,&m=12ff34,&f=12ff38,&d1=12ff40,&s=12

從上面的結果我們可以得到如下幾個結論:

1. 如果結構體中含有指針,是很容易出問題的,從上面的結果中(高亮)部分可以看到字符串的輸出結果是不一樣的,這說明,在進行寫入文件的時候,char*所指向的字符串沒有寫入文件,只是將指針寫入,當從文件中讀出結構體,再次得到這個指針的時候,由於程序運行的內存位置變化,所以原來指針所指向的內容也變了,所以輸出也變了。

2. 還有一個比較重要的是結構體的內存對其問題(之前也討論過)。可以看到,不同的編譯器采取的方式是不一樣的。 gcc中的結構體大小為40字節,而VC下是48個字節。

並且GCC下,結構體內存的起始位置是4的倍數,而VC中是8的倍數。這是因為,結構體的起始地址與其中所包含的擁有最多字節的類型有關。之前也說過,因為GCC的處理方式是如果結構體內有超過4個字節的類型,那么結構體起始位置以4的倍數開始, 而VC中是以最大字節數的為准。

ps:4的倍數就是地址的最低兩位是00,8的倍數就是地址最低三位為000

然后我分別在linux下讀入winxp寫的結構體文件和在winxp下讀入linux下寫的結構體文件,兩個平台下的程序都崩潰了。

 

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM