使用fread将文件的内容读取到一个结构中

如何解决使用fread将文件的内容读取到一个结构中

| 在“ Unix环境中的高级编程”一书中,有一部分(第251页的第8.14节),作者向我们展示了“ acct”结构的定义(用于存储会计记录信息)。然后,他显示了一个程序,在该程序中,他将文件中的会计数据读取到结构中(其关键部分是):
fread (&acdata,sizeof(acdata),1,fp)
我遇到的麻烦是,我听说C编译器有时会在内存中重新排列结构的元素,以便更好地利用空间(由于对齐问题)。因此,如果该代码只是获取了文件的所有内容并将其粘贴到acdata中(并且文件的内容被安排为与struct定义中指定的顺序匹配),则如果struct的某些元素已经移动,那么如果我在代码中引用它们,则可能无法达到预期的效果(因为文件中的数据没有按照结构体在内存中的方式进行重新排列)。 我想念的是什么(由于我得到的东西似乎不可靠)? 感谢您的帮助(如果我在程序上做错了事,我深表歉意-这是我第一次发布)     

解决方法

        是 您的程序将是稳定的。 您的问题触动了您并未真正要求的可移植性建议的篝火。您似乎要问的问题是“此代码模式和我的程序稳定吗?”。答案是肯定的。 您的结构不会重新排序。 C99特别禁止重新布置结构构件。1 同样,布局和对齐方式也不取决于优化级别。如果这样做的话,所有程序,所有库例程,内核,所有内核接口等都必须完全以相同的优化级别构建。 用户还必须永远跟踪上面列出的已被编译为系统一部分的每个接口的优化级别。 内存对齐规则实际上是一种隐藏的ABI。如果不添加非常专业的定义上很少使用的编译器标志,它们就无法更改。它们往往可以在不同的编译器上正常工作。 (否则,上面标识的系统的每个元素也都必须由同一编译器编译,否则将无用。支持给定系统的每个编译器都使用完全相同的对齐规则。否则,任何操作都将无效。)编译器标记为变更对齐策略通常旨在用于给定OS的编译器配置中。 现在,您的二进制文件布局虽然完全合理,但却有些陈旧。它具有某些缺点。虽然这些都不是阻止显示的东西,并且通常都不值得重写应用程序,但它们包括: 调试二进制文件很困难 它们确实以单字节顺序和单个对齐策略锁定。在(很可能,越来越不可能)需要移植到新体系结构的情况下,最终可能需要使用memcpy(3)来解压缩记录。不是世界末日。 它们不是结构化的。诸如YAML甚至是XML之类的东西都是自解析的,因此在文件中读取变得容易得多,并且某些类型的文件操作可以使用工具来完成。更重要的是,文件格式本身变得更加灵活。但是,在C和C ++中,利用自动分析对象的能力受到限制。 据我了解Paxdiablo的要求,他希望我同意存在编译器选项和编译指示,如果使用这些选项和编译指示,它们会更改对齐规则。确实如此。显然,仅出于特定原因使用这些选项。 1. C99 6.7.2.1(13)在结构对象中,非位字段成员以及其中位字段的单位 居住的地址按照声明的顺序增加。     ,担心! 您担心并关注此问题是正确的。这是一个令人烦恼的问题,通常发生在将源代码携带到另一台计算机上时,这种计算机具有不同的体系结构,甚至略有不同,并且可能具有不同的OS或不同的编译器。在那里编译程序;并希望您的结构在
fwrite( )
fread( )
上保持完整。或者,当您在结构中添加一个1字节的变量时,重新编译并将二进制文件发送给所有朋友。由于某些神秘的原因,您的程序无法再在他们的计算机上运行。 有时它会(偶然)起作用,而您永远不会注意到问题。有时它不起作用,而您将头发拉出几天。 问题与结构成员的重新安排无关。编译器不这样做。它也与优化无关。 问题是字节对齐,下面提到的Wikipedia文章告诉您如何修复结构,以使它们始终正确对齐。注意字节对齐始终是一个好主意。否则,您的程序将无法移植。而且,更糟的是,您在whiz-bang x86-64上仔细编译并突然分发给所有客户的程序无法在其32位计算机上运行。 同样重要:也要注意struct成员的长度和对齐方式。 Wikipedia上有一篇很好的文章,介绍了详细信息。这是非常值得一读的。 我会警惕执行此工作的特定于编译器的编译指示,但仅针对该编译器。如果您在代码中添加了杂注,那么您的程序将不再是C语言。     ,        如果您在其他编译器,更高版本的编译器甚至使用不同的编译时选项来编译代码,则结构的布局(填充和对齐,但不会顺序)可能会更改。 它不会在同一编译程序的运行之间发生变化-这将是一场噩梦:-) 因此,只要进行读取的程序是相同的程序(或者从技术上讲,是在编译时将相同结构布局编码到其中的任何程序),就可以正常工作。 C99标准的相关部分包括:   6.2.6.1/1:除本节中规定的以外,所有类型的表示均未指定。      6.2.6.1/6(在该子句中仅提及结构):当值存储在结构或联合类型的对象中(包括成员对象中)时,与任何填充字节相对应的对象表示形式的字节均未指定价值观。即使结构或联合对象的成员的值可能是陷阱表示,结构或联合对象的值也永远不会是陷阱表示。 这是该子句中唯一提到的结构填充。换句话说,这取决于实现,他们甚至不需要记录它(未指定,而不是实现定义的,这需要记录文件)。   6.7.2.1/13:...结构对象内可能存在未命名的填充,但在其开头没有。      6.7.2.1/15:结构或联合的末尾可能存在未命名的填充。 如果要创建程序的版本1.1,并且使用不同的结构布局(新的编译器,不同的编译器选项,
#pragma pack
等),那么很快就会发现您在单元测试期间遇到了问题(应该包括加载)在先前版本的文件中)。 在这种情况下,您可以在1.1程序中包含一些\ intelligence \(智能),它们可以识别较早的文件布局并在输入数据时对其进行转换。这就是为什么好的文件格式通常会带有版本指示符(对于文件布局版本,而不是程序版本)作为该文件的第一项。 例如,我的很多应用程序都使用应用程序标识符以及文件开头的16位整数来指示它是什么应用程序和版本,并且程序的文件加载器部分至少可以处理当前版本和先前版本。版本(以及通常创建的每个版本)。 程序版本和文件布局版本是分开的-例如,如果您发布十个版本的程序而无需更新文件布局,它们可能会漂移。     ,        结构将根据其在内存中的写入方式写入文件。顺序将是相同的。但是,在读写之间混合使用编译器可能是一个问题。     

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


依赖报错 idea导入项目后依赖报错,解决方案:https://blog.csdn.net/weixin_42420249/article/details/81191861 依赖版本报错:更换其他版本 无法下载依赖可参考:https://blog.csdn.net/weixin_42628809/a
错误1:代码生成器依赖和mybatis依赖冲突 启动项目时报错如下 2021-12-03 13:33:33.927 ERROR 7228 [ main] o.s.b.d.LoggingFailureAnalysisReporter : *************************** APPL
错误1:gradle项目控制台输出为乱码 # 解决方案:https://blog.csdn.net/weixin_43501566/article/details/112482302 # 在gradle-wrapper.properties 添加以下内容 org.gradle.jvmargs=-Df
错误还原:在查询的过程中,传入的workType为0时,该条件不起作用 <select id="xxx"> SELECT di.id, di.name, di.work_type, di.updated... <where> <if test=&qu
报错如下,gcc版本太低 ^ server.c:5346:31: 错误:‘struct redisServer’没有名为‘server_cpulist’的成员 redisSetCpuAffinity(server.server_cpulist); ^ server.c: 在函数‘hasActiveC
解决方案1 1、改项目中.idea/workspace.xml配置文件,增加dynamic.classpath参数 2、搜索PropertiesComponent,添加如下 <property name="dynamic.classpath" value="tru
删除根组件app.vue中的默认代码后报错:Module Error (from ./node_modules/eslint-loader/index.js): 解决方案:关闭ESlint代码检测,在项目根目录创建vue.config.js,在文件中添加 module.exports = { lin
查看spark默认的python版本 [root@master day27]# pyspark /home/software/spark-2.3.4-bin-hadoop2.7/conf/spark-env.sh: line 2: /usr/local/hadoop/bin/hadoop: No s
使用本地python环境可以成功执行 import pandas as pd import matplotlib.pyplot as plt # 设置字体 plt.rcParams['font.sans-serif'] = ['SimHei'] # 能正确显示负号 p
错误1:Request method ‘DELETE‘ not supported 错误还原:controller层有一个接口,访问该接口时报错:Request method ‘DELETE‘ not supported 错误原因:没有接收到前端传入的参数,修改为如下 参考 错误2:cannot r
错误1:启动docker镜像时报错:Error response from daemon: driver failed programming external connectivity on endpoint quirky_allen 解决方法:重启docker -> systemctl r
错误1:private field ‘xxx‘ is never assigned 按Altʾnter快捷键,选择第2项 参考:https://blog.csdn.net/shi_hong_fei_hei/article/details/88814070 错误2:启动时报错,不能找到主启动类 #
报错如下,通过源不能下载,最后警告pip需升级版本 Requirement already satisfied: pip in c:\users\ychen\appdata\local\programs\python\python310\lib\site-packages (22.0.4) Coll
错误1:maven打包报错 错误还原:使用maven打包项目时报错如下 [ERROR] Failed to execute goal org.apache.maven.plugins:maven-resources-plugin:3.2.0:resources (default-resources)
错误1:服务调用时报错 服务消费者模块assess通过openFeign调用服务提供者模块hires 如下为服务提供者模块hires的控制层接口 @RestController @RequestMapping("/hires") public class FeignControl
错误1:运行项目后报如下错误 解决方案 报错2:Failed to execute goal org.apache.maven.plugins:maven-compiler-plugin:3.8.1:compile (default-compile) on project sb 解决方案:在pom.
参考 错误原因 过滤器或拦截器在生效时,redisTemplate还没有注入 解决方案:在注入容器时就生效 @Component //项目运行时就注入Spring容器 public class RedisBean { @Resource private RedisTemplate<String
使用vite构建项目报错 C:\Users\ychen\work>npm init @vitejs/app @vitejs/create-app is deprecated, use npm init vite instead C:\Users\ychen\AppData\Local\npm-