C语言代码优化示例(二)
一. 起源
在整理系统平台的代码时候,看到了一些原来同事编写的代码,有感于这些代码的编写方法和效率问题,挑出一段有代表意义的代码和大家分享如何改进代码的编码效率和提高代码的执行速率,同时降低代码对内存的消耗.
二. 原始代码(下面简称代码A)
void InintExchangeRateSet(void){double ExchangeRateTab[] = {1.0, // 美元6.924, //人民币30.36, //新台币106.1, //日元7.807, //港币0.5108, //英镑1.039, //瑞法郎1.151, //澳元1.3657, //新元0.6415, //欧元1.018 //其它};SetSystemResouce((INT8U *)ExchangeRateTab, SYS_CVS_ECR, 0, YS_CVS_ECR_LEN);}
三. 优化代码(下面简称代码B)
static const double ExchangeRateTab[] = {1.0, // 美元6.924, //人民币30.36, //新台币106.1, //日元7.807, //港币0.5108, //英镑1.039, //瑞法郎1.151, //澳元1.3657, //新元0.6415, //欧元1.018 //其它};void InintExchangeRateSet(void){SetSystemResouce((INT8U *)ExchangeRateTab, SYS_CVS_ECR, 0, YS_CVS_ECR_LEN);}
四. 代码解析
编译器使用的是mips-linux-gcc 3.3.1版本,使用O2优化.
上面的代码非常简单,而且A和B实现的是相同的功能 (满足前提条件是SetSystemResouce的第一个参数是一个常量指针,实际情况也是如此).而且对代码并没有做什么改动,只是修改了一个数组的定义方法,来达到优化的目的.
double ExchangeRateTab修改为static const double ExchangeRateTab
可能大家对这种优化感到迷茫和不解: 这不是一样的吗?有什么变化?
产生这种想法的根本原因是对编译器的行为不了解导致的,我们对比分析一下编译产生的两段代码就能立即明白这其中的道理:
代码A编译后的汇编代码:
8001e348 <InintExchangeRateSet>:8001e348: 27bdff90 addiu sp,sp,-112 //耗费更多的堆栈空间8001e34c: 3c028027 lui v0,0x80278001e350: 24423618 addiu v0,v0,13848 //数组的访问地址:0x802736188001e354: afbf0068 sw ra,104(sp)8001e358: 27a30010 addiu v1,sp,16 //这部分代码是一个循环体,作用8001e35c: 24440050 addiu a0,v0,80 //就是拷贝ROM区域的数组值到8001e360: 8c450000 lw a1,0(v0) //到堆栈空间.8001e364: 8c460004 lw a2,4(v0) //编译器在编译代码A的时候,因为数组是8001e368: 8c470008 lw a3,8(v0) //定义在堆栈上的(使用局部变量定义), 编8001e36c: 8c48000c lw t0,12(v0) //译器认为调用者是有可能修改这个数组8001e370: ac650000 sw a1,0(v1) //的,而且数组包含有初值, 所以在后面的8001e374: ac660004 sw a2,4(v1) // ROM区域有一个常量数据保存区.由于8001e378: ac670008 sw a3,8(v1) //这个原因,它必须老老实实的使用8001e37c: ac68000c sw t0,12(v1) //代码把ROM区域的初值拷贝到堆栈,以便8001e380: 24420010 addiu v0,v0,16 //应对后续代码可能对数组的修改8001e384: 1444fff6 bne v0,a0,8001e360 <InintExchangeRateSet+0x18>8001e388: 24630010 addiu v1,v1,168001e38c: 27a40010 addiu a0,sp,16 //参数18001e390: 24050cee li a1,3310 //参数28001e394: 00003021 move a2,zero //参数38001e398: 8c490000 lw t1,0(v0)8001e39c: 8c4a0004 lw t2,4(v0)8001e3a0: ac690000 sw t1,0(v1)8001e3a4: ac6a0004 sw t2,4(v1)8001e3a8: 0c00a26a jal 800289a8 <SetSystemResouce>8001e3ac: 24070058 li a3,88 //参数48001e3b0: 8fbf0068 lw ra,104(sp)8001e3b4: 03e00008 jr ra8001e3b8: 27bd0070 addiu sp,sp,112代码A访问的数组资源: //常量数组的ROM保存地址(不包括黑体部分)80273610: 00020063 00000000 00000000 3ff00000 c..............?80273620: 0e560419 401bb22d f5c28f5c 403e5c28 ..V.-..@/...(/>@80273630: 66666666 405a8666 353f7cee 401f3a5e fffff.Z@.|?5^:.@80273640: 3dd97f63 3fe05879 76c8b439 3ff09fbe c..=yX.?9..v...?80273650: f9db22d1 3ff26a7e 3e425aee 3ff5d9e8 ."..~j.?.ZB>...?80273660: 020c49ba 3fe4872b 5e353f7d 3ff049ba .I..+..?}?5^.I.?80273670: 00000001 00000002 00000002 00000004 ................80273680: 00000001 00000002 00000003 00000004 ................80273690: 00000006 00000008 0000000c 00000010 ................802736a0: 00000018 00000020 00000000 00000000 .... ...........
代码B编译后的汇编代码:
8001e348 <InintExchangeRateSet>:8001e348: 27bdffe8 addiu sp,sp,-248001e34c: 3c048027 lui a0,0x80278001e350: 248435c8 addiu a0,a0,13768 //数组的访问地址: 0x802735c8,//直接传递给函数的第一个参数a08001e354: 24050cee li a1,3310 //参数28001e358: 00003021 move a2,zero //参数38001e35c: afbf0010 sw ra,16(sp) 8001e360: 0c00a256 jal 80028958 <SetSystemResouce>8001e364: 24070058 li a3,88 //参数48001e368: 8fbf0010 lw ra,16(sp)8001e36c: 03e00008 jr ra8001e370: 27bd0018 addiu sp,sp,24代码A访问的数组资源:802735c8 <ExchangeRateTab>: //常量数组的ROM保存地址802735c8: 00000000 3ff00000 0e560419 401bb22d .......?..V.-..@802735d8: f5c28f5c 403e5c28 66666666 405a8666 /...(/>@fffff.Z@802735e8: 353f7cee 401f3a5e 3dd97f63 3fe05879 .|?5^:.@c..=yX.?802735f8: 76c8b439 3ff09fbe f9db22d1 3ff26a7e 9..v...?."..~j.?80273608: 3e425aee 3ff5d9e8 020c49ba 3fe4872b .ZB>...?.I..+..?80273618: 5e353f7d 3ff049ba 00000001 00000002 }?5^.I.?........80273628: 00000002 00000004 00000001 00000002 ................80273638: 00000003 00000004 00000006 00000008 ................80273648: 0000000c 00000010 00000018 00000020 ............ ...
对比两段代码的编译结果,很明显的代码B的代码量大大缩减(由29条指令缩减到11条指令),没有一条多余的代码,同时提高了代码的执行速度(少了资源拷贝的循环体:见代码A的注释).而对于两种实现方法,保存常量的空间并没有发生任何变化.
五. 结束语
优化永无至境,但是一开始采用好的编码方法将获得更高的效率,降低不必要的工作和性能开销.
在此抛砖引玉,希望有更多的人在编写代码的时候获得一些灵感和方法,写出更加高效和精简的代码.
有一句话共勉: 好的设计不是无法再添加代码,而是再也没有办法减少代码
原创文章,欢迎转载,请注明来源,未经书面允许,请勿用于商业用途。
C语言代码优化示例(二)相关推荐
- C语言代码优化示例(一)
在实际产品的软件开发过程中,很多时候会对代码的性能提出要求,追求最快的速度,提高程序运行效率,改善用户体验等,此时此刻,对代码的优化就非常有必要了,掌握代码的优化方法和技巧就很有必要了. 我们用下面的 ...
- 一起学习C语言:函数(二)
上一篇<一起学习C语言:函数(一)> 中,我们了解了函数的概念,以及函数实现与程序编译过程.本章节,我们分析内部函数和外部函数,以及变量的生命周期. 章节预览: 4. 外部函数与内部函数 ...
- 关于一些C语言代码优化的方法,我慷慨解囊了大家酌情收藏
关于一些C语言代码优化的方法,我慷慨解囊了大家酌情收藏 简介 在最近的一个项目中,我们需要开发一个运行在移动设备上但不保证图像高质量的轻量级JPEG库.期间,我总结了一些让程序运行更快的方法.在本篇文 ...
- c语言动态生成二维数组,C语言 动态创建二维数组
/*C语言 如何动态创建二维数组 转化为一维数组申请数组,创建和释放都比较简单 */ #include #include #include #define RANK 10 #define COLUMN ...
- 国二C语言文字选择程序选择,全国计算机等级考试二级C语言题型总结(二)——选择循环结构程序设计部分.doc...
全国计算机等级考试二级C语言题型总结(二)--选择循环结构程序设计部分 C语言第二部分上机题型总结 选择结构部分: if结构题型总结 (案例1) 企业发放的奖金根据利润提成.利润(I)低于或等于10万 ...
- 【数字信号处理】LTI 系统因果性与稳定性示例 ( 示例一 | 示例二 )
文章目录 一.系统因果性与稳定性示例一 二.系统因果性与稳定性示例二 一.系统因果性与稳定性示例一 判断系统的 因果性 与 稳定性 : y(n)=1N∑k=0N−1x(n−k)y(n) = \cfra ...
- C结构体工具DirectStruct(综合示例二)
2019独角兽企业重金招聘Python工程师标准>>> C结构体工具DirectStruct(综合示例二) 1.编写定义文件,用工具dsc处理之,自动生成XML转换代码和ESQL代码 ...
- 数据结构源码笔记(C语言):二叉平衡树的相关操作算法
//二叉平衡树的相关运算 #include<stdio.h> #include<malloc.h> #include<string.h>typedef char I ...
- C语言指针和二维数组
二维数组在概念上是二维的,有行和列,但在内存中所有的数组元素都是连续排列的,它们之间没有"缝隙".以下面的二维数组 a 为例: int a[3][4] = { {0, 1, 2, ...
最新文章
- python selenium 处理弹窗_python selenium 弹出框处理的实现
- kafka存储机制与读写流程
- JavaScript语言基础11
- 拒绝了对对象 'XXX' (数据库 'XXX',架构 'dbo')的 SELECT 权限
- Android 界面滑动实现---Scroller类 从源码和开发文档中学习(让你的布局动起来)...
- 第2章 数字之魅——求二进制中1的个数
- python3利用smtplib通过qq邮箱发送邮件
- mysql btree检索策略_MySQL之Btree索引和HASH索引的区别以及索引优化策略
- php左连接,如何在php中对左联接查询返回的数组数据进...
- 解决org.apache.ibatis.binding.BindingException: Invalid bound statement (not found)错误
- 【原创】全面剖析飞凌2440,6410开发板选型指南
- java list move_Java中List最重要的特性
- 数字图像算术编码python_算术编码的python实现
- 双人对战的球类游戏ios源码项目
- 新型的Hbb项目目录结构
- 凹凸贴图(Bump Map)实现原理以及与法线贴图(Normal Map)的区别
- 货拉拉2021岗位招聘内推计划开始啦
- 【GTASA】如何解锁Locked的DFF模型
- Web 开发项目的6个最佳Java框架
- stm32 RO RW ZI
热门文章
- 【工具配置】【Windows】Cuda和cudnn安装教程(保姆级)
- 攻防世界_难度8_happy_puzzle
- http-server : 无法加载文件 C:\Users\mes\AppData\Roaming\npm\http-server.ps1,因为在此系统上禁止运行脚本。有关详细信息, 请参阅 http
- jquery学习笔记及常用函数封装
- 【ChatBot】走进聊天机器人
- 电子类专业的毕业后就业方向
- 有什么占内存小又好玩的手游,占内存小的手机游戏
- 如何降低与心仪的人的尬聊次数,成功上位 ^_^
- netcore 在centos部署时,服务启动失败,错误码145
- 菜鸟程序员的第一次写作经历