在一次使用MDk的编译优化等级比较高的时候发现编译不优化时功能正常,开了优化等级02就出现异常,调试中看了很多博客总结一下。

  • 一个变量,如果你的主程序要用到,同时中断还要用到,要加volatile修饰。告诉编译器这个变量是可能随时发生变化的,使得编译器编译程序的时候,每次都从RAM里面读取数据,而不是使用之前缓存到寄存器里面的值。
  • 对于多任务的程序,如果一个公共变量被多个任务用到也要加volatile修饰。
  • 同时变量定义的时候用了关键字volatile修饰,但是在其他文件引用时不加volatile变量修饰一样会被编译器优化掉。现则反过来想想,原因还是很简单的,MDK编译多个文件时是分别编译,最后再用链接器链接,当编译的时候一个模块引用另外一个模块的变量,完全是靠的变量声明,如果声明都不加volatile,那么引用的模块肯定会把变量当成普通变量的,再反推一下,如果原变量没有加volatile,但是声明的时候加了volatile,是不是引用的模块会将这个变量当成volatile型变量呢

  C编译器是以每个C文件作为基本编译单元的,称为模块,被编译为obj;而模块之间的函数或变量访问都是通过标号来实现的,标号本身没有任何属性,只是提供给链接器使用的一个符号名称而已,标号的属性完全就靠调用的地方的原型声明来决定的!因此,你在一个.C模块中定义为volatile,仅仅是在.C模块中告诉编译器不要优化而已,在另外的模块内使用了这个变量,而它们是不知道该变量是什么属性的,所以只有靠原型声明来告诉编译器这些信息了。

最后简单的给总结一下:别小看原型声明,它是联系各个模块的桥梁,是各种输出符号的属性信息所在。编译原理不懂就是比较亏啊。。。

最后补充一下MDK中关于编译的一些选项说明:

USE Cross-Module Optimization

跨模块优化从先前的构建中获取信息,并使用它将UNUSED函数放入其中在相应的目标文件中拥有自己的ELF部分。 此选项也称为链接器反馈,需要构建程序两次以利用它来减少代码大小。

USE MicroLIBMicroLIB

是一个针对嵌入式平台优化过的C库可以减少应用程序的大小。他是标准C库的一个子集,以提供功能和代码大小之间的权衡,比如一些标准C库的memcpy函数应用到微控制器上就运行速度来说比较慢。原文(Some of the standard C library functions such as memcpy() are slower, while some features of the default library are not supported.)这里还说默认的库还不支持一些特性:

包括:

  1. 操作系统功能,例如 abort(),exit(),time(),system(),getenv()
  2. 宽字符和多字节支持,例如 mbtowc(),wctomb()
  3. stdio文件I/O函数,stdin,stdout和stderr除外
  4. 位置无关且线程安全的代码

Link-Time Code Generation(这个选项新版好像没有了)
链接时代码生成指示编译器以中间格式创建对象,以便链接器可以执行进一步的代码优化。 这使代码生成器可以同时查看所有对象的跨文件依赖性,从而允许它应用更高级别的优化。 链接时代码生成可以减少代码大小,并使您的应用程序运行得更快。
Optimization Levels

不同的优化级别允许您在级别之间进行权衡已编译代码中可用的调试信息以及代码的性能。以下优化级别可用:
-O0应用最小优化。
大多数优化都被关闭,生成的代码具有最佳的调试视图。
-O1应用受限优化。
例如,删除未使用的内联函数和未使用的静态函数。在这个优化级别,编译器还应用自动优化,例如删除冗余代码和重新排序指令以避免互锁情况。生成的代码经过合理优化,具有良好的调试视图。
-O2应用高优化(这是默认设置)。
在此级别应用的优化利用了ARM对处理器体系结构的深入了解,利用给定目标的特定于处理器的行为。它生成优化良好的代码,但有限调试视图。
-O3应用最积极的优化。
优化符合用户的-Ospace / -Otime选择。默认情况下,多文件编译是启用,这会导致更长的编译时间,但会提供最高级别的优化。

Optimize for Time
“优化时间”复选框使编译器进行优化,更加注重实现最佳效果检查时的性能(-Otime)或未选中时的最小代码大小(-Ospace)。
取消选中Optimize for Time就意味着选择-Ospace选项,该选项指示编译器执行优化以可能增加的执行时间为代价来减小Image文件大小。例如,使用非内联函数调用而不是大型结构副本的内联代码。 这是默认选项。从中运行编译器时命令行,使用'-Ospace'调用此选项选中Optimize for -Otime选项,该选项指示编译器以最快的速度优化代码执行时间,有可能增加image文件大小。建议编译时间关键部分您的代码使用-Otime,其余使用-Ospace指令。

Split Load and Store Multiples
指示编译器将涉及大量寄存器的LDM和STM指令拆分为一系列较少多个寄存器的加载/存储。这意味着16个寄存器的LDM可以分成4个独立的LDM,每个LDM由4个寄存器组成。此选项有助于减少没有缓存或写缓冲区的ARM系统上的中断延迟,以及使用零等待状态32位内存的系统。
例如,ARM7和ARM9处理器只能在指令边界上执行异常。如果在无缓存的ARM7和ARM9系统中的16个寄存器的LDM开始时发生异常,则系统将在获取异常之前完成对存储器的16次访问。根据存储器仲裁系统,这可能导致非常高的中断延迟。将LDM拆分为4个寄存器的4个独立LDM意味着处理器在加载最多4个寄存器后将采用异常,从而大大减少中断延迟。选择此选项可提高系统的整体性能。
One ELF Section per Function
选项告诉编译器将所有函数放入它们各自的ELF部分。 这允许链接器删除未使用的函数.ELF代码部分通常包含许多函数的代码。 链接器通常只能删除未使用的ELF部分,而不是未使用的函数。 只有当所有内容都未使用时,才能删除ELF部分。因此,将每个函数拆分为自己的ELF部分允许编译器轻松识别哪些未使用,并将其删除。选择此选项会增加编译代码所需的时间,但可以提高性能。

常见优化目标选项

最小的目标代码:

选中
• The MicroLIB C library
• Cross-module optimization
• Optimization level 2 (-O2)

最好的代码表现性能:

选中
• Cross-module optimization
• Optimization level 3 (-O3)
• Optimize for time

最后总结一句话,只要代码逻辑够严密无论是多高的编译优化等级都是不会出问题的,所以在资源不是出现了必须要优化的时候不建议优化代码,自己增加实现难度而已,反之如果你追求功能的稳定可以在优化等级下发现0级优化下存在的问题进行完善在改回0级优化编译此时代码的逻辑漏洞会减少。

MDK编译优化笔记的更多相关文章

  1. 15个问题自查你真的了解java编译优化吗?

    摘要:为什么C++的编译速度会比java慢很多?二者运行程序的速度差异在哪? 了解了java的早期和晚期过程,就能理解这个问题了. 本文分享自华为云社区<你真的了解java编译优化吗?15个问题 ...

  2. MDK的优化应用

    MDK的优化应用 http://blog.163.com/zhaojun_xf/blog/static/300505802011291384721/ 使用Keil/MDK这么多年了,一直都没有使用它的 ...

  3. MDK的优化应用(转)

    源:http://blog.163.com/zhaojun_xf/blog/static/300505802011291384721/ 使用Keil/MDK这么多年了,一直都没有使用它的代码优化功能. ...

  4. U3D开发性能优化笔记(待增加版本.x)

    http://blog.csdn.net/kaitiren/article/details/45071997 此总结由自己经验及网上收集整理优化内容 包括: .代码方面: .函数使用方面: .ui注意 ...

  5. GCC 编译优化指南(转)

    GCC 编译优化指南(转) http://www.jinbuguo.com/linux/optimize_guide.html 作者:金步国 版权声明 本文作者是一位开源理念的坚定支持者,所以本文虽然 ...

  6. 关于java字符串编译优化问题

    情景一:不好的字符串拼接习惯    起因是这样的:一个大牛在写了一篇关于java字符串优化问题的讲解,他提到:不要使用strObj+otherValue的方法将otherValue转换为字符串形式,因 ...

  7. GCC 编译优化指南

    转自: http://www.jinbuguo.com/linux/optimize_guide.html GCC 编译优化指南 作者:金步国[www.jinbuguo.com] 版权声明 本文作者是 ...

  8. Android App性能优化笔记之一:性能优化是什么及为什么?

    By Long Luo   周星驰的电影<功夫>里面借火云邪神之口说出了一句至理名言:“天下武功,唯快不破”. 在移动互联网时代,同样如此,留给一个公司的窗口往往只有很短的时间,如何把握住 ...

  9. GCC编译优化指南【作者:金步国】

    GCC编译优化指南[作者:金步国] GCC编译优化指南 作者:金步国 版权声明 本文作者是一位自由软件爱好者,所以本文虽然不是软件,但是本着 GPL 的精神发布.任何人都可以自由使用.转载.复制和再分 ...

随机推荐

  1. RabbitMQ默认情况下不保证每次都把消息传递

    有意思,RabbitMQ默认情况下是不保证每次都把消息传递的,很多情况下我们都是这样发送数据的,    channel.BasicPublish(QUEUE_NAME, String.Empty, n ...

  2. Codeforces Round #597 (Div. 2) E. Hyakugoku and Ladders 概率dp

    E. Hyakugoku and Ladders Hyakugoku has just retired from being the resident deity of the South Black ...

  3. 第04组 Beta冲刺(2/5)

    队名:new game 组长博客 作业博客 组员情况 鲍子涵(队长) 过去两天完成了哪些任务 验收游戏素材 学习Unity 2D Animation系统 基本做完了人物的各个动画 接下来的计划 冲击E ...

  4. java之运算符的优先级

    优先级 运算符 结合性 1 () [] 从左往右 2 ! +(正) -(负) ++ -- 从右往左 3 * / %  从左往右 4 << >> >>> 从左往 ...

  5. SQLServer某个库log日志过大,无法收缩日志文件 ,因为该文件结尾的逻辑日志文件正在使用

    问题描述: 今天看到user库日志备份方面很久,然后查看到user库这个log日志很大 图片是我已经解决了,然后现在可以收缩的大小 解决方法: 1.先备份user库日志,因为很大,所以要等很久,这个只 ...

  6. 划词标注1——使用svg绘制换行文本并自动识别库中字典数据

    业务需求 给出一段文本,自动识别出文本中包含的关键字信息,关键字是库里已知的数据,根据类型的不同显示出不同的颜色 业务分析 1)采用css:文本识别出来后,根据识别出的文本更改对应文本的dom,通过更 ...

  7. LINUX CFS 调度tick逻辑,即check_preemt_tick解析

    计算当前task在这个tick周期实际用时delta_exetime, 更新当前task的vruntime; 根据权重,重新计算调度period,计算当前task的应得时间片slice(idle_ru ...

  8. OpenGL光照3:光源

    本文是个人学习记录,学习建议看教程 https://learnopengl-cn.github.io/ 非常感谢原作者JoeyDeVries和多为中文翻译者提供的优质教程 的内容为插入注释,可以先跳过 ...

  9. RocketMQ(4)---RocketMQ核心配置讲解

    RocketMQ核心配置讲解 RocketMQ的核心配置在broker.conf配置文件里,下面我们来分析下它. 一.broker.conf配置 下面只列举一些常用的核心配置讲解. 1.broker. ...

  10. shell 编程练习题2

    需求1:使用root用户清空/var/log/messages日志,并每次执行保留最近100行 ​ 1.必须是root用户 ​ 2.需要保留最后100行 [root@manager if]# cat ...