结构填充在C struct序列化中的影响(保存到文件)

时间:2011-04-05 19:04:47

标签: c file serialization struct padding

我在C中有以下结构:

typedef struct sUser {
    char name[nameSize];
    char nickname[nicknameSize];
    char mail[mailSize];
    char address[addressSize];
    char password[passwordSize];
    int totalPoints;
    PlacesHistory history;
    DynamicArray requests;
}User;

typedef struct sPlacesHistory {
    HistoryElement array[HistorySize];
    int occupied;
    int last;
}PlacesHistory;

和功能:

void serializeUser( User * user, FILE * fp ) {
    fwrite( user, nameSize + nicknameSize + mailSize + addressSize + passwordSize + sizeof( int ) + sizeof( PlacesHistory ), 1, fp );
    serializeDynamicArray( user -> requests, fp );
}

User * loadUser( FILE * fp ) {
    User * user = malloc( sizeof( User ) );
    fread( user, nameSize + nicknameSize + mailSize + addressSize + passwordSize + sizeof( int ) + sizeof( PlacesHistory ), 1, fp );
    user -> requests = loadDynamicArray( fp );

    return user;
}

当我加载struct User,并且我打印该用户(从文件加载)时,placesHistory的字段“last”的值为255或-1,具体取决于PlacesHistory结构的字段顺序。但是我保存的用户在该成员上有-1。

所以当我得到255时,显然是错的.. 我怀疑这与struct padding有关。

我怎样才能这样做,使结构中的字段顺序无关紧要?
或者我需要遵循哪些标准才能使事情正常进行? 我是否需要一次fwrite / fread一个成员? (我想为效率问题避免这种情况)
我是否需要首先序列化为数组而不是文件? (我希望不会......因为这意味着事先知道我所有结构的大小,因为mallocated数组 - 这意味着额外的工作为每个非简单结构创建一个函数来知道它的大小)

注意:*大小是定义的常量
注2:DynamicArray是指向另一个结构的指针。

3 个答案:

答案 0 :(得分:1)

是的,它可能与totalPointshistory前面的填充有关。

您可以写出sizeof(User) - sizeof(DynamicArray)并回读相同内容。当然,只要结构定义和编译器不变,这只会兼容。如果您不需要从一个版本的程序中获取序列化数据以与另一个版本兼容,那么上述内容应该可以正常工作。

答案 1 :(得分:0)

为什么要单独添加所有元素?这只是增加了很多错误的空间。无论何时更改结构,如果忘记更改添加大小的所有位置,代码可能会中断(事实上,为什么每次都要添加它?)。

而且,正如您所怀疑的那样,您的代码也没有考虑结构填充,因此您可能在数据块的末尾缺少最多三个字节(如果您的最大元素是4个字节)。

为什么不sizeof(User)来获取您正在读/写的数据量?如果您不希望保存部分内容(如请求),则在结构中使用结构。 (编辑:或者,就像rlibby建议的那样,只需减去你不想阅读的部分的大小。)

我的猜测是你的字符串大小不能被4整除,所以你短3个字节,因此,你应该读“0xffffffff”(= -1),但最后只读“0xff000000” “(当使用小端时,= 255,并假设你的结构最初被清零)。

答案 2 :(得分:0)

填充可能是你的问题,因为

nameSize + nicknameSize + mailSize + addressSize + passwordSize + sizeof( int ) + sizeof( PlacesHistory ) != sizeof( User ) 

所以最后一个成员(和结构中的最后一个)保持单元化。要检查这一点,请在从文件中读取之前执行memset(,0,sizeof(User))。

要解决此问题,请先使用#pragma pack(push,1),然后再使用#pragma pack(pop)