使用标准C读取文件遇到的结构体对齐问题及其解决办法
作者:朱金灿
来源:http://blog.csdn.net/clever101
同事使用标准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接口去读一个结构体的缓冲区常常不准确,其实也不科学,因为文件设计者在设计文件时文件的各个成员肯定都是紧挨着的,因此是使用简单类型逐个去读取。
如何解决这个问题呢?如前文所述,使用简单类型逐个去读取肯定是可以的,但是如果文件比较复杂的话,这意味着要写比较多的代码。有没有更好的办法呢?也有,可以将结构体做如下定义:
/* 对齐结构成员到1字节 */
#ifdef __GNUC__
#define GNUC_PACKED __attribute__((packed))
#else
#define GNUC_PACKED
#endif #ifdef __arm
#define ARM_PACKED __packed
#else
#define ARM_PACKED
#endif #if defined(WIN32) || defined(_WIN64)
#pragma pack(1)
#endif
ARM_PACKED
typedef struct {
unsigned short id;
long len;
}GNUC_PACKED Chunk3DS;
#if defined(WIN32) || defined(_WIN64)
#pragma pack()
#endif
参考文献:
使用标准C读取文件遇到的结构体对齐问题及其解决办法的更多相关文章
- c语言_文件操作_FILE结构体解释_涉及对操作系统文件FCB操作的解释_
1. 文件和流的关系 C将每个文件简单地作为顺序字节流(如下图).每个文件用文件结束符结束,或者在特定字节数的地方结束,这个特定的字节数可以存储在系统维护的管理数据结构中.当打开文件时,就建立了和文件 ...
- C语言文件操作 FILE结构体
内存中的数据都是暂时的,当程序结束时,它们都将丢失.为了永久性的保存大量的数据,C语言提供了对文件的操作. 1.文件和流 C将每个文件简单地作为顺序字节流(如下图).每个文件用文件结束符结束,或者在特 ...
- C++ 读取文本文件内容到结构体数组中并排序
成绩排行:从Score.txt文件读取学生信息,对其进行排序,按回答题数从大到小排,若相等,按分数从小到大排 #include<iostream> #include<fstream& ...
- Golang Json文件解析为结构体工具-json2go
代码地址如下:http://www.demodashi.com/demo/14946.html 概述 json2go是一个基于Golang开发的轻量json文件解析.转换命令行工具,目前支持转换输出到 ...
- 结构体:探析C#文件方式读写结构体
最近直在研究Net Micro Framework字体文件(tinyfnt)由于tinyfnt文件头部有段描述数据所以很想 定义个结构体像VC样直接从文件中读出来省得用流个个解析很是麻烦 没有想到在中 ...
- 函数定义从零开始学C++之从C到C++(一):const与#define、结构体对齐、函数重载name mangling、new/delete 等
今天一直在学习函数定义之类的问题,下午正好有机会和大家共享一下. 一.bool 类型 逻辑型也称布尔型,其取值为true(逻辑真)和false(逻辑假),存储字节数在不同编译系统中可能有所不同,VC+ ...
- const与#define、结构体对齐、函数重载name mangling、new/delete 等
一.bool 类型 逻辑型也称布尔型,其取值为true(逻辑真)和false(逻辑假),存储字节数在不同编译系统中可能有所不同,VC++中为1个字节. 声明方式:bool result; result ...
- C语言中结构体对齐问题
C语言中结构体对齐问题 收藏 关于C语言中的结构体对齐问题 1,比如: struct{short a1;short a2;short a3;}A;struct{long a1;short a2;}B; ...
- 《PHP7底层设计与源码实现》学习笔记2——结构体对齐
书里给了一段代码,假如有个结构体如下: struct test { char a; int b; long c; void* d; int e; cha ...
随机推荐
- Ubuntu系统的安装(虚拟机) 并配置C/C++编译器
一.系统的初始化配置 1.配置静态IP和DNS 配置静态IP 1.sudo vim /etc/network/interfaces,修改文件内容如下: auto eth0 #表示让网卡开机自动挂载e ...
- dubbo源码阅读之SPI
dubbo SPI SPI,全程Service Provider interface, java中的一种借口扩展机制,将借口的实现类注明在配置文件中,程序在运行时通过扫描这些配置文件从而获取全部的实现 ...
- MySQL笔记(3)---文件
1.前言 第二章简单记录了一下InnoDB存储引擎的一个基本内容,介绍了保证高效插入的Insert Buffer,change Buffer和确保数据安全的write ahead log以及doubl ...
- CentOS下使用crontab命令来定时执行任务
原文地址:http://www.centoscn.com/CentOS/help/2015/0424/5261.html crontab命令 是用来让使用者在固定时间或固定间隔执行程序之用,换句话说, ...
- unsigned/signed int/char类型表示的数值范围
一个32位的signed int类型整数表示的范围:-2^31~2^31-1 一个32位的unsigned int类型整数表示的范围: 0~2^32-1 一个8位的signed char类型整数表示的 ...
- JavaScript中十种一步拷贝数组的方法
JavaScript中我们经常会遇到拷贝数组的场景,但是都有哪些方式能够来实现呢,我们不妨来梳理一下. 1.扩展运算符(浅拷贝) 自从ES6出现以来,这已经成为最流行的方法.它是一个很简单的语法,但是 ...
- CustomSqlSessionFactoryBean
import java.io.File; import java.net.JarURLConnection; import java.net.URL; import java.util.ArrayLi ...
- Ansible工作流程详解
1:Ansible的使用者 ------>Ansible的使用者来源于多种维度,(1):CMDB(Configuration Management Database,配置管理数据库),CMDB存 ...
- python学习之内存机制
不可变对象(字符串.元组) 1. a = 1 首先在内存中创建对象1,并记录对象的引用计数为1次. id(a) 查看变量a引用的对象的内存地址 2. b = 1 内存中已存在对象1,变量b引用对象1, ...
- JavaScript学习总结(二)——延迟对象、跨域、模板引擎、弹出层、AJAX示例
一.AJAX示例 AJAX全称为“Asynchronous JavaScript And XML”(异步JavaScript和XML) 是指一种创建交互式网页应用的开发技术.改善用户体验,实现无刷新效 ...