【原创&交流】使用标准C库读文件时需要注意的一个问题

clever101
博客专家认证
2011-08-27 09:36:39
链接:使用标准C库读文件时需要注意的一个问题

晚上编一个程序,使用标准C库读取文件,发现总是读取不对。我感觉很奇怪。
我定义了如下一个结构体:


// 定义块的结构
typedef struct {
unsigned short id;
long len;
} Chunk3DS;



我想读取文件中关于这个结构的信息。我是这样读取的:

if (fread(&chunk,sizeof(Chunk3DS),1,m_fp)!=1)
{
return FALSE;
}


但是读取的内容总是不对。

突然我想到结构体内存对齐这档子事,于是我把读取代码改为:

Chunk3DS chunk;
if (fread(&chunk.id,sizeof(unsigned short),1,m_fp)!=1)
{
return FALSE;
}
if (fread(&chunk.len,sizeof(long),1,m_fp)!=1)
{
return FALSE;
}



接着我测试了一下:

int nShortSize = sizeof(unsigned short); // 等于2
int nLongSize = sizeof(long); // 等于4
int SstructSize = sizeof(Chunk3DS); // 等于8



整整差了两个字节,难怪读取的内容不对。现在我发现由于结构体内存对齐的缘故(结构体内存对齐的原理网上的相关文章很多,在这不进行详述),使用fread接口去读一个结构体的缓冲区常常不准确,其实也不科学,因为文件设计者在设计文件时文件的各个成员肯定都是紧挨着的,因此是使用简单类型逐个去读取。





...全文
400 20 打赏 收藏 转发到动态 举报
AI 作业
写回复
用AI写文章
20 条回复
切换为时间正序
请发表友善的回复…
发表回复
自由建客 2011-08-31
  • 打赏
  • 举报
回复
这总是个麻烦事,还有大小端问题呢!
匚匚 2011-08-31
  • 打赏
  • 举报
回复

学习了
[Quote=引用 12 楼 supermegaboy 的回复:]
将结构体写入文件时是不应该整体写入读出的,因为无法保证写入读出时具有一致的对齐系数,即使在写入读出代码段中通过#pragma pack规定对齐系数,仍会存在读取到缓冲区中的数据对齐与当前环境不一致的问题,所以将结构体整体写入文件不是一个良好的设计,会带来难以查找的隐患。

老老实实逐个成员写入读出就行了,况且,无用的padding写入文件带来的空间浪费是完全没有必要的。
[/Quote]
ljhhh0123 2011-08-28
  • 打赏
  • 举报
回复
你现在才知道,不算晚。
AnYidan 2011-08-28
  • 打赏
  • 举报
回复
[Quote=引用 4 楼 clever101 的回复:]
引用 2 楼 jackyjkchen 的回复:

既然你用的是结构体,写入文件的时候也应该是以结构体写入而不是分两次写入

这样就可以用结构体读了


我读取的是3DS文件,不是自定义格式的。
[/Quote]

于写入的格式保持一致
zsc_ericluo 2011-08-28
  • 打赏
  • 举报
回复
[Quote=引用 12 楼 supermegaboy 的回复:]
将结构体写入文件时是不应该整体写入读出的,因为无法保证写入读出时具有一致的对齐系数,即使在写入读出代码段中通过#pragma pack规定对齐系数,仍会存在读取到缓冲区中的数据对齐与当前环境不一致的问题,所以将结构体整体写入文件不是一个良好的设计,会带来难以查找的隐患。

老老实实逐个成员写入读出就行了,况且,无用的padding写入文件带来的空间浪费是完全没有必要的。
[/Quote]
学习鸟,DDD!
clever101 2011-08-28
  • 打赏
  • 举报
回复
[Quote=引用 12 楼 supermegaboy 的回复:]

将结构体写入文件时是不应该整体写入读出的,因为无法保证写入读出时具有一致的对齐系数,即使在写入读出代码段中通过#pragma pack规定对齐系数,仍会存在读取到缓冲区中的数据对齐与当前环境不一致的问题,所以将结构体整体写入文件不是一个良好的设计,会带来难以查找的隐患。

老老实实逐个成员写入读出就行了,况且,无用的padding写入文件带来的空间浪费是完全没有必要的。
[/Quote]

嗯,我是支持这一观点的!

icemornings 2011-08-28
  • 打赏
  • 举报
回复

/* 对齐结构成员到1字节 */
#ifdef __GNUC__
#define GNUC_PACKED __attribute__((packed))
#else
#define GNUC_PACKED
#endif

#ifdef __arm
#define ARM_PACKED __packed
#else
#define ARM_PACKED
#endif

#ifdef WIN32
#pragma pack(1)
#endif
ARM_PACKED
typedef struct {
unsigned short id;
long len;
}GNUC_PACKED Chunk3DS;
#ifdef WIN32
#pragma pack()
#endif
飞天御剑流 2011-08-28
  • 打赏
  • 举报
回复
噢,对了,这个问题与标准C库没有关系,而属于策略问题。
飞天御剑流 2011-08-28
  • 打赏
  • 举报
回复
将结构体写入文件时是不应该整体写入读出的,因为无法保证写入读出时具有一致的对齐系数,即使在写入读出代码段中通过#pragma pack规定对齐系数,仍会存在读取到缓冲区中的数据对齐与当前环境不一致的问题,所以将结构体整体写入文件不是一个良好的设计,会带来难以查找的隐患。

老老实实逐个成员写入读出就行了,况且,无用的padding写入文件带来的空间浪费是完全没有必要的。
JXLFZ 2011-08-28
  • 打赏
  • 举报
回复
要是这个结构体里的数据是一次写入的,也能一次读出?
我为自己袋盐 2011-08-28
  • 打赏
  • 举报
回复
学习鸟!
clever101 2011-08-27
  • 打赏
  • 举报
回复
[Quote=引用 7 楼 jackyjkchen 的回复:]

引用 6 楼 clever101 的回复:

引用 3 楼 worldy 的回复:

引用楼主 clever101 的回复:
链接:使用标准C库读文件时需要注意的一个问题

晚上编一个程序,使用标准C库读取文件,发现总是读取不对。我感觉很奇怪。
我定义了如下一个结构体:


C/C++ code

// 定义块的结构
typedef struct {
unsigne……
[/Quote]

呵呵,一时没理解。这个结构网上的高手给3ds文件的块结构作的定义。用unsigned short或者是强调是非负数吧。


5t4rk 2011-08-27
  • 打赏
  • 举报
回复
[Quote=引用 2 楼 jackyjkchen 的回复:]

既然你用的是结构体,写入文件的时候也应该是以结构体写入而不是分两次写入

这样就可以用结构体读了
[/Quote]

一次读入
或者你不用short用long呗
jackyjkchen 2011-08-27
  • 打赏
  • 举报
回复
[Quote=引用 6 楼 clever101 的回复:]

引用 3 楼 worldy 的回复:

引用楼主 clever101 的回复:
链接:使用标准C库读文件时需要注意的一个问题

晚上编一个程序,使用标准C库读取文件,发现总是读取不对。我感觉很奇怪。
我定义了如下一个结构体:


C/C++ code

// 定义块的结构
typedef struct {
unsigned short id;
long ……
[/Quote]
人家意思是用int……
clever101 2011-08-27
  • 打赏
  • 举报
回复
[Quote=引用 3 楼 worldy 的回复:]

引用楼主 clever101 的回复:
链接:使用标准C库读文件时需要注意的一个问题

晚上编一个程序,使用标准C库读取文件,发现总是读取不对。我感觉很奇怪。
我定义了如下一个结构体:


C/C++ code

// 定义块的结构
typedef struct {
unsigned short id;
long len;
}……
[/Quote]


unsigned short id用于标识块的,不用不行的。
liutengfeigo 2011-08-27
  • 打赏
  • 举报
回复
哦.谢了
clever101 2011-08-27
  • 打赏
  • 举报
回复
[Quote=引用 2 楼 jackyjkchen 的回复:]

既然你用的是结构体,写入文件的时候也应该是以结构体写入而不是分两次写入

这样就可以用结构体读了
[/Quote]

我读取的是3DS文件,不是自定义格式的。
worldy 2011-08-27
  • 打赏
  • 举报
回复
[Quote=引用楼主 clever101 的回复:]
链接:使用标准C库读文件时需要注意的一个问题

晚上编一个程序,使用标准C库读取文件,发现总是读取不对。我感觉很奇怪。
我定义了如下一个结构体:


C/C++ code

// 定义块的结构
typedef struct {
unsigned short id;
long len;
} Chunk3DS;
……
[/Quote]

既然结构体short类型不能减少内存的消耗,那么short不使用也罢!
jackyjkchen 2011-08-27
  • 打赏
  • 举报
回复
既然你用的是结构体,写入文件的时候也应该是以结构体写入而不是分两次写入

这样就可以用结构体读了
那年的月光 2011-08-27
  • 打赏
  • 举报
回复
以前还不知道,谢!

70,024

社区成员

发帖
与我相关
我的任务
社区描述
C语言相关问题讨论
社区管理员
  • C语言
  • 花神庙码农
  • 架构师李肯
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧