性能优化相关_第1页
性能优化相关_第2页
性能优化相关_第3页
性能优化相关_第4页
性能优化相关_第5页
已阅读5页,还剩17页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

C程序优化之路本文讲述在编写C程序代码的常用优化办法,分为I/O篇,内存篇,算法篇,MMX汇编篇。一.I/O篇如果有文件读写的话,那么对文件的访问将是影响程序运行速度的一大因素。提高文件访问速度的主要办法有两个:一是采用内存映射文件,二是使用内存缓冲。下面是一组测试数据(见《UNIX环境高级编程》3.9节),显示了用18种不同的缓存长度,读1468802字节文件所得到的结果。缓冲大小用户CPU(秒)系统CPU(秒)时钟时间(秒)循环次数(秒)123.8397.9423.41468802212.3202.0215.273440146.1100.6107.236720183.050.754.0183601161.525.327.091801320.712.813.74590162295112114762557385120.01.01.1286910240.00.60.6143520480.00.40.471840960.00.40.435981920.00.30.3180163840.00.30.390327680.00.30.345655360.00.30.3231310720.00.30.312可见,一般的当内存缓冲区大小为8192的时候,性能就已经是最佳的了,这也就是为什么在H.263等图像编码程序中,缓冲区大小为8192的原因(有的时候也取2048大小)。使用内存缓冲区方法的好处主要是便于移植,占用内存少,便于硬件实现等。下面是读取文件的C伪码:intLen;BYTEbuffer[8192];ASSERT(buffer==NULL);Ifbufferisempty{Len=read(File,buffer,8192);If(len==0)Nodataandexit;}但是如果内存比较大的时候,采用内存映射文件可以达到更佳性能,并且编程实现简单。内存映射的具体使用说明见msdnOctober2001中的PlatformSDKDocumentation_BaseServices_FileStorage_FileMappingo下面是一点建议:内存映射文件不能超过虚拟内存的大小,最好也不要太大,如果内存映射文件接近虚拟内存大小的时候,反而会大大降低程序的速度(其实是因为虚拟内存不足导致系统运行效率降低),这个时候,可以考虑分块映射,但是我觉得如果这样,还不如直接使用内存缓冲来得直接一些。可以将两种方法统一使用,如我在编大图像文件数据处理的时候(因为是Unix工作站,内存很大GB单位)使用了内存映射文件,但是为了最佳性能,也使用了一行图像缓存,这样在读取文件中数据的时候,就保证了仅仅是顺序读写(内存映射文件中,对顺序读写有专门的优化)。在写文件的时候使用内存映射文件要有一点小技巧:应该先创建足够大的文件,然后将这个文件映射,在处理完这个文件的时候,用函数SetFilePointer和SetEndOfFile来对文件进行截尾。对内存映射文件进行操作与对内存进行操作类似(使用起来就象数组一样),那么如果有大块数据读写的时候,切记使用memcpy()函数(或者CopyMemory()函数)总之,如果要使用内存映射文件,必须:1.处理的文件比较的小,2.处理的文件很大,但是运行环境内存也很大,并且一般在运行该程序的时候不运行其他消耗内存大的程序,同时用户对速度有特别的要求,而且对内存占用没有什么要求。如果以上两个条件不满足的时候,建议使用内存缓冲区的办法。本文来自CSDN博客,转载请标明出处:/liyuming1978/archive/2002/12/10/19069.aspxC程序优化之路(二)收藏本文讲述在编写C程序代码的常用优化办法,分为I/O篇,内存篇,算法篇,MMX汇编篇。二.内存篇在上一篇中我们讲述了如何优化文件的读写,这一篇则主要讲述对内存操作的优化,主要有数组的寻址,指针链表等,还有一些实用技巧。I.优化数组的寻址在编写程序时,我们常常使用一个一维数组a[MxN]来模拟二维数组a[N][M],这个时候访问a[]—维数组的时候:我们经常是这样写a[jxM+i](对于a[j][i])。这样写当然是无可置疑的,但是显然每个寻址语句jxM+i都要进行一次乘法运算。现在再让我们看看二维数值的寻址,说到这里我们不得不深入到C编译器在申请二维数组和一维数组的内部细节上一一实际在申请二位数组和一维数组,编译器的处理是不一样的,申请一个a[N][M]的数组要比申请一个a[MxN]的数组占用的空间大!二维数组的结构是分为两部分的:是一个指针数组,存储的是每一行的起始地址,这也就是为什么在a[N][M]中,a[j]是一个指针而不是aj][0]数据的原因。是真正的MxN的连续数据块,这解释了为什么一个二维数组可以象一维数组那样寻址的原因。(即a[j][i]等同于(a[0])[jxM+i])清楚了这些,我们就可以知道二维数组要比(模拟该二维数组的)一维数组寻址效率高。因为aj][i]的寻址仅仅是访问指针数组得到j行的地址,然后再+i,是没有乘法运算的!所以,在处理一维数组的时候,我们常常采用下面的优化办法:(伪码例子)inta[M*N];int*b=a;fbr(...){b[...]=...b[…]=…;b+=M;}这个是遍历访问数组的一个优化例子,每次b+=M就使得b更新为下一行的头指针。当然如果你愿意的话,可以自己定义一个数组指针来存储每一行的起始地址。然后按照二维数组的寻址办法来处理一维数组。不过,在这里我建议你干脆就直接申请一个二维数组比较的好。下面是动态申请和释放一个二维数组的C代码。intget_mem2Dint(int***array2D,introws,intcolumns) //h.263源代码{inti;if((*array2D=(int**)calloc(rows,sizeof(int*)))==NULL)no_mem_exit(1);if(((*array2D)[0]=(int*)calloc(rows*columns,sizeof(int)))==NULL)no_mem_exit(1);for(i=1;i<rows;i++)(*array2D)[i]=(*array2D)[i-1]+columns;returnrows*columns*sizeof(int);}voidfree_mem2D(byte**array2D){if(array2D){if(array2D[0])free(array2D[0]);elseerror("free_mem2D:tryingtofreeunusedmemory",100);free(array2D);}else{error("free_mem2D:tryingtofreeunusedmemory",100);}}顺便说一下,如果你的数组寻址有一个偏移量的话,不要写为 a[x+offset],而应该为b=a+offset,然后访问b[x]。不过,如果你不是处理对速度有特别要求的程序的话,这样的优化也就不必要了。记住,如果编普通程序的话,可读性和可移值性是第一位的。II.从负数开始的数组在编程的时候,你是不是经常要处理边界问题呢?在处理边界问题的时候,经常下标是从负数开始的,通常我们的处理是将边界处理分离出来,单独用额外的代码写。那么当你知道如何使用从负数开始的数组的时候,边界处理就方便多了。下面是静态使用一个从一1开始的数组:inta[M];int*pa=a+1;现在如果你使用pa访问a的时候就是从一1到M-2了,就是这么简单。(如果你动态申请a的话,free(a)可不要free(pa)因为pa不是数组的头地址)我们需要链表吗相信大家在学习《数据结构》的时候,对链表是相当熟悉了,所以我看有人在编写一些耗时算法的时候,也采用了链表的形式。这样编写当然对内存的占用(似乎)少了,可是速度呢?如果你测试:申请并遍历10000个元素链表的时间与遍历相同元素的数组的时间,你就会发现时间相差了百倍!(以前测试过一个算法,用链表是1分钟,用数组是4秒钟)。所以这里我的建议是:在编写耗时大的代码时,尽可能不要采用链表!其实实际上采用链表并不能真正节省内存,在编写很多算法的时候,我们是知道要占用多少内存的(至少也知道个大概),那么与其用链表一点点的消耗内存,不如用数组一步就把内存占用。采用链表的形式一定是在元素比较少,或者该部分基本不耗时的情况下。(我估计链表主要慢是慢在它是一步步申请内存的,如果能够象数组一样分配一个大内存块的话,应该也不怎么耗时,这个没有具体测试过。仅仅是猜想:P)本文来自CSDN博客,转载请标明出处:/liyuming1978/archive/2002/12/09/19070.aspxC程序优化之路(三) liyuming1978@163.com本文讲述在编写C程序代码的常用优化办法,分为I/O篇,内存篇,算法篇。MMX本来我也想归在这里的,但是由于内容和标题不太符和,决定换一个名字,叫MMX技术详解,和H263视频压缩技术中的MMX应用两篇文章。三.算法篇在上一篇中我们讲述了对内存操作的优化,这一篇则主要讲述一些常用的优化算法。这个东东太多,内容可能会有点凌乱,见谅。I.从小处说起:先说说一些小地方先:比如n/2写为n>>1这个是常用的方法,不过要注意的是这两个不是完全等价的!因为:如果n=3的话,n/2=1;n>>1=1;但是,如果n=-3的话,n/2=-1;n>>1=-2所以说在正数的时候,他们都是向下取整,但是负数的时候就不一样了。(在JPG2000中的整数YUV到RGB变换一定要使用>>来代替除法就是这个道理)还有就是a=a+1要写为a++;a=a+b要写为a+=b(估计一般用VB的才会写a=a+1:P)将多种运算融合:比如a[i++];就是先访问a[i],再令i加1;从汇编的角度上说,这个确实是优化的,如果写为a[i],和i++的话,有可能就会有两次的对i变量的读,一次写(具体要看编译器的优化能力了),但是如果a[i++]的话,就一定只读写i变量一次。不过这里有一个问题要注意:在条件判断内的融合一定要小心,比如:(idct变换中的0块判断,陈王算法)if(!((x1=(blk[8*4]<<8))I(x2=blk[8*6])I(x3=blk[8*2])I(x4=blk[8*1])I(x5=blk[8*7])(x6=blk[8*5])I(x7=blk[8*3])))在条件判断中融合了赋值语句,但是实际上如果条件为真的话,是不需要这些赋值语句的,也就是说当条件真的时候,多了一些垃圾语句,这些是在h263源码上的问题,虽然这些垃圾语句使得计算0块的时候,时间增加了30%,但是由于idct仅仅占1%的时间,0块又仅仅30%~70%的时间,所以这些性能损失是没有什么关系的。(这是后来我用汇编改写源码的时候得到的结论)。这里也说明了,程序优化一定重点在最耗时的地方。对于不耗时的代码优化是没有太大的实用意义的。.以内存换速度:天下总是难有双得的事情,编程也是一样,大多数情况,速度同内存(或者是性能,比如说压缩性能什么的)是不可兼得的。目前程序加速的常用算法一个大方面就是利用查表来避免计算(比如在jpg有huffman码表,在YUV到RGB变换也有变换表)这样原来的复杂计算现在仅仅查表就可以了,虽然浪费了内存,不过速度显著提升,还是很划算的。在数据库查询里面也有这样的思想,将热点存储起来以加速查询。现在介绍一个简单的例子,(临时想的,呵呵):比如,在程序中要经常(一定要是经常!)计算1000到2000的阶乘,那么我们可以使用一个数组a[1000]先把这些值算好,保留下来,以后要计算1200!的时候,查表a[1200-1000]就可以了。化零为整由于零散的内存分配,以及大量小对象建立耗时很大,所以对它们的优化有时会很有效果,比如上一篇我说的链表存在的问题,就是因为大量的零散内存分配。现在就从一个vb的程序说起,以前我用vb给别人编小程序的时候,(呵呵,主要是用vb编程比vc快,半天就可以写一个)在使用MSFlexGrid控件的时候(就是一个表格控件),发现如果一行一行的增加新行,刷新速度十分的慢,所以我就每次增加100行,等到数据多到再加新行的时候,再加100行,这样就“化零为整”了,使用这样的方法,刷新的速度比原来快了n倍!其实这样的思想应用很多,如:程序运行的时候,其实就占用了一定的空间,后来的小块内存分配是先在这个空间上的,这就保证了内存碎片尽可能的少,同时加快运行速度。条件语句或者case语句将最有可能的放在前面优化效果不明显。想得到就用吧,想不到就算了。为了程序的可读性,不去做那些编译器可以做的或者优化不明显的处理:这个是很重要的,一个普通程序的好坏,主要是它的可读性,可移植性,可重用性,然后才是它的性能。所以,如果编译器本身可以帮助我们优化的话,我们就没有必要写那些大家都不怎么看得懂的东西。比如a=52(结束)一16(起始);这样写可能是因为在别人读程序的时候,一下就明白了a的含义。我们不用写为a=36,因为编译器是会帮我们算出来的。IV.具体情况具体分析:具体情况具体分析,这是放之四海而皆准的真理。没有具体的分析,就不能针对问题灵活应用解决的办法。下面我就说说分析的方法。即如何找到程序的耗时点:(从最简单的办法说起,先说明一个函数GetTickCount()这个函数在头尾各调用一次,返回值相减就是程序的耗时,精确到1ms)对于认为是比较耗时的函数,运行两次,或者将函数内部的语句注释掉(要保证程序可以运行),看看多(或者少了)多少时间。这个办法简单不精确。每个地方都用GetTickCount(涵数测试时间,注意GetTickCount()只能精确到ms。一般的小于10ms就不太精确了。使用另外一个函数QueryPerformanceCounter(&Counter)和QueryPerformanceFrequency(&Frequency),前面计算cpu时钟周期,后面是cpu频率相除就是时间。不过如果你要精确到这一步的话,建议将进程设置为最高级别,防止它被阻塞。最后讲讲我处理的一个程序:程序要求我忘了,反正里面有一个函数,函数里面有一个大的循环,循环内部的处理比较耗时。结果最初程序表现出来的状况是开始还很快,越到后面越慢;我在跟踪程序中变量的时候,发现最初的循环在循环几次后就跳出了,而后面的循环次数越来越多。找到了为什么慢的原因,就可以对症下药了,我的处理是每次循环不是从头开始,而是从上一次循环跳出的地方开始左右循环(因为可能下一次循环跳出的地方别上一次的小,所以也要遍历前面的),这样程序的速度在后面也很快了。我讲这个的道理就是在实际运用中,要具体的分析程序慢的真正原因,才能达到最佳的优化效果。本文来自CSDN博客,转载请标明出处:/liyuming1978/archive/2002/12/11/19071.aspxMMX开发文档IMMX简介Intel的MMXT^术是对Intel体系结构(ia)指令集的扩展。该技术使用了单指令多数据技术(SIMD)技术,以并行方式处理多个数据元素,从而提高了多媒体和通讯软件的运行速度。MMXtm指令集增加了57条新的操作码和一个新的64位四字数据类型。MMX™技术提高了很多应用程序的执行性能,例如活动图像、视频会议、二维图形和三维图形。几乎每一个具有重复性和顺序性整数计算的应用程序都可以从MMXT^术中受益。对于8位、16位和32位数据元素的处理,改善了程序的性能。一个MMXTM指令可一次操作8个字节,且在一个时钟周期内完成两条指令,也就是说,可在一个时钟周期内处理16个数据元素。另外,为增强性能,MMXT^术为其它功能释放了额外的处理器周期。以前需要其它硬件支持的应用程序,现在仅需软件就能运行。更小的处理器占用率给更高程度的并发技术提供了条件,在当今众多的操作系统中这些并发技术得到了利用。在基于Intel的分析系统中,某些功能的性能提高了50%到400%。这种数量级的性能扩展可以在新一代处理器中得到体现。在软件内核中,其速度得到更大的提高,其幅度为原有速度的三至五倍。MMX的缺点:由于MMX的运算指令必须在数据配对整齐的时候才能使用,所以使用MMX指令要比普通的汇编指令多余许多分组配对的指令,如果运算不是特别的整齐的话,就要浪费大量的时间在数据的配对上,所以说MMX指令也不是万能的,也有其很大的缺陷。同时MMX指令在处理16位数据的时候才能发挥最大的作用,处理8位数据要有一点技巧。而处理32位数据,MMX指令几乎没有什么加速能力。(考虑分组耗时的话)IIMMX基本指令集具体细节请参阅《INTEL体系结构MMX技术程序员参考手册》第五章2.1拷贝指令movq:64位数据拷贝,如果内存8位对齐的话,是一个64位写,否则2个32位写。movd:32位数据拷贝,注意:如果从内存向MMX寄存器拷贝,MMX高32位清零!2.2分组指令分组指令是MMX特有的,所以对于它我们要特别的关注。分组指令基本上可以分为2类,一类是不带符号紧缩的,一类是带符号紧缩的。现在我们分别予以介绍:punpcklbw/punpcklwd/punpckldq(l表示低位分组,bw8位,wd16位,dq32位):它是简单的将两个MMX寄存器的低32位交错组合为一个64位数据。所以它是不能将长数据转换为短数据的。packuswb将16位数据转换为无符号的8位数据。所以可以将两个MMX寄存器不交错的合为一个64位数据。packsswb/packssdw将32位一》16位,16位一》8位,都是有符号的数据。2.3运算指令加法运算指令:paddb(w)(d):没有越界保护的加法,当越界的时候仅仅丢弃超出范围的高位比特,(b)(w)(d)分别为8,16,32位加法;paddsb(w):具有越界保护的有符号加法,当上溢的时候为0x7fff,下溢的时候为0x8000;paddusb(w):具有越界保护的无符号加法,当上溢的时候为0x7fff,下溢的时候为0x0。减法运算指令同上;add改为sub。乘法指令:pmullw/pmulhw是4个16位数据的乘法,pmullw中是结果的低16位,pmulhw是结果的高16位。pmaddwd乘加指令。2.4逻辑指令,移位指令和EMMS指令细节参见《INTEL体系结构MMX技术程序员参考手册》。IIIMMX经典处理策略数据输入输出:在输入数据的时候,经典的处理方法是将一个数组整个“Loadw到MMX寄存器中。这样简单同时利用了MMX64位读写数据的能力,提高了性能。同样在输出的时候,也是将一个64位MMX寄存器中的数据内容整个“Store^a内存中。如果实在是不能这样处理的话,就要利用移位指令了。比如说将一个MMX内的4个16位数据分别拷贝到不同的内存变量(或者16位通用寄存器中)x1,x2,x3,x4,那么可以这样处理:movd eax,mm1psrlqmm1,32movd ebx,mm1TOC\o"1-5"\h\zmov x1,axmov x2,bxshr eax,16shr ebx,16mov x3,axmov x4,bx可见如果不采用数组形式的话,输入输出将十分的麻烦。数据分组以及求绝对值的方法等:细节请参阅《INTEL体系结构MMX™技术开发者手册》第五章IV自定义组合指令①八位无符号数的移位:

在MMX指令集中是没有8位数据的移位指令的,但是有的时候我们确实需要,所以可以用以下两个指令来实现:psrlqmm0,1pandmm0,0x7f7f7f7f7f7f7f7fpandmm0,0x7f7f7f7f7f7f7f7f②如何防止计算过程中越界:是可以使用的,但是如果结果差错1都不可容忍的话,就要进行比如在计算的时候,我们有(x1+x2+1)>>1,这个时候x1+x2就会越界(8位数据),那么我们就不得不使用替代了办法,比如(x1>>1+x2>>1是可以使用的,但是如果结果差错1都不可容忍的话,就要进行pandmm0,0x01010101010101//保留数据的最后一位pandmm1,0x01010101010101//保留数据的最后一位pormm0,mm1paddusbpandmm0,0x01010101010101//保留数据的最后一位pandmm1,0x01010101010101//保留数据的最后一位pormm0,mm1paddusbmmx,mm0//修正数据(x1>>2+x2>>2):这个处理是通用的pandmm0,0x03030303030303//保留数据的最后两位pandmm1,0x03030303030303//保留数据的最后两位pandmm0,0x03030303030303//保留数据的最后两位pandmm1,0x03030303030303//保留数据的最后两位paddusbmm0,mm1psrlqmm0,2psrlqmm0,2pandmm0,0x3f3f3f3f3f3f3f3fpaddusbmmx,mm0pandmm0,0x3f3f3f3f3f3f3f3fpaddusbmmx,mm0符号扩展指令:mm0:*,*A,B=>现在要符号扩展为mm0:(A符号)A,(A符号)Bmovqmm1,mm0pcgtmmm1,0 II比较皿皿0,生成mml:(A符号)(B符号)()()punpcklwdmm0,mm1分组指令除了基本的分组指令以外,我们还可以利用移位指令和pandpor指令来实现分组的功能,移位主要是要产生0,这样pormm0,mml就可以将mm0和mml合并了。比如:mm0(*,*,A,B)mm1(0,0,C,D)贝Upsllq mm0,32por mm0,mm1=>(A,B,C,D)当然这个例子我们可以用普通的分组指令实现,但是在某些复杂的处理中,这样的处理是必须的。总之,要灵活运用MMX的现有指令来实现自己需要的功能。VMMX编程心得使用MMX技术进行编程,目的就是要提高运算速度,所以,对于如何尽可能的提高代码的效率,我们是要特别关注的。这里,我介绍一些需要注意的事项。①尽可能的提高内存访问的容量,我们可以看看下面的代码:for(j=0;j<h;j++){d[0]=s[0];d[1]=s[1];d[2]=s[2];d[3]=s[3];d[4]=s[4];d[5]=s[5];d[6]=s[6];d[7]=s[7];d[8]=s[8];d[9]=s[9];d[10]=s[10];d[11]=s[11];d[12]=s[12];d[13]=s[13];d[14]=s[14];d[15]=s[15];s+=lx2;d+=lx;}_asm{pushfmovedx,dwordptrhxorecx,ecxmovesi,dwordptrsmovedi,dwordptrdmoveax,lx2movebx,lxAGAIN:movq mm0,byteptr[esi]movq mm1,byteptr[esi+8]movq byteptr[edi],mm0movq byteptr[edi+8],mm1add esi,eaxadd edi,ebxadd ecx,1cmp ecx,edxjl AGAINemmspopf}仅仅将几个8位的写,改为64位的写,测试得到速度提升了25%,同样的道理,我们要尽可能的将几个movq写在一起,这样可以提高5%左右的速度。原C代码的效率也是很高的,它不用数组的【】【】来寻址,而是将s+=lx2;从而将二维数组的寻址改为一维数组的寻址。尽可能的减少寻址的复杂度,这也是一种高效的办法。还有一点就是如果将原来的简单赋值改为memcpy()的话,可以提高大约10%的速度。这也是提高了数据流通容量的关系。②一些要注意的地方:尽可能的使用static变量,访问这样的变量是很快的=访问立即数的速度由于只有一个mmx移位寄存器,(移位分组指令)是不能配对的3.不要在eax使用完,使用ax,不要使用完一个皿皿1,就立即使用它3.可以这样立即使用mml,movqmm2,mm1movqmm1,mm3(Z顺序是可以的)(4个以上)movq尽可能的在一起,前提是在一起的mov不要使用一样的mmx寄存器moveax,[esi]([esi+2*eax])访问寻址的内存是特别的慢的同上stow也是很慢的(movcx,n; loop是很慢的,如果可能,要展开循环)尽可能的在寄存器中完成操作,不要去访问内存用变量名访问变量,尤其是static的,是很快.访问寻址的内存的速度下降》数据不对齐8位的速度下降》指令不配对的速度下降所以在传统的代码优化的方法中,构造数组,然后将运算变为查表的方法,有的时候在MMX技术内反而会降低速度。(这个时候,如果真的用查表有提升速度的话,建议采用段地址+偏移量的办法)本文来自CSDN博客,转载请标明出处:/liyuming1978/archive/2002/12/30/19072.aspxC程序优化5年10月15日点击次对程序进行优化,通常是指优化程序代码或程序执行速度。优化代码和优化速度实际上是一个予盾的统一,一般是优化了代码的尺寸,就会带来执行时间的增加,如果优化了程序的执行速度,通常会带来代码增加的副作用,很难鱼与熊掌兼得,只能在设计时掌握一个平衡点。一、程序结构的优化1、程序的书写结构虽然书写格式并不会影响生成的代码质量,但是在实际编写程序时还是应该尊循一定的书写规则,一个书写清晰、利于以后的维护。在书写程序时,特别是对于While、for、do...while、L..case等语句或这些语句嵌套组合时,应采用“缩格”的书写形式,日户标识符除要遵循标识符的命名规则以外,一般不要用代数符号(如a、b、量名,应选取具有相关含义的英文单词(或缩写)或汉语拼音作为标识符,以增生,如:count、numberl、red、work等。m级程序设计语言,提供了十分完备的规范化流程控制结构。因此在采用C语艾用系统程序时,首先要注意尽可能采用结构化的程序设计方法,这样可使整芦结构清晰,便于调试和维护。于一个较大的应用程序,通常将整个程序按功莫块,不同模块完成不同的功能。各个模块可以分别编写,甚至还可以由不同一般单个模块完成的功能较为简单,设计和调试也相对容易一些。在C语言可以认为是一个模块。所谓程序模块化,不仅是要将整个程序划分成若干个要的是,还应该注意保持各个模块之间变量的相对独立性,即保持模块的独立全局变量等。对于一些常用的功能模块,还可以封装为一个应用程序库,以便妾调用。但是在使用模块化时,如果将模块分成太细太小,又会导致程序的执入和退出一个函数时保护和恢复寄存器占用了一些时间)。史程中,对于经常使用的一些常数,如果将它直接写到程序中去,一旦常数的数必、须逐个找出程序中所有的常数,并逐一进行修改,这样必然会降低程序的可应尽量当采用预处理命令方式来定义常数,而且还可以避免输入错误。句扁译(ifdef)的地方就使用条件编译而不使用if语句,有利于减少编译生成的代弋中各种运算执行的优先顺序不太明确或容易混淆的地方应当采用圆括号勺优先顺序。一个表达式通常不能写得太复杂,如果表达式太复杂,时间久了容易看得懂,不利于以后的维护。Il数,在使用之前,应对函数的类型进行说明,对函数类型的说明必须保证它与贲类型一致,对于没有参数和没有返回值类型的函数应加上“void”明。如果马的长度,可以将程序中一些公共的程序段定义为函数,在Keil中的高级别优如果需要缩短程序的执行时间,在程序调试结束后,将部分函数用宏定义来该在程序调试结束后再定义宏,因为大多数编译系统在宏展开之后才会报错,昔的难度。局变量,多用局部变量。因为全局变量是放在数据存储器中,定义一个全局变-个可以利用的数据存储器空间,如果定义了太多的全局变量,会导致编译器0以分配。而局部变量大多定位于MCU内部的寄存器中,在绝大多数MCU操作速度比数据存储器快,指令也更多更灵活,有利于生成质量更高的代码,而勺占用的寄存器和数据存储器在不同的模块中可以重复利用。编译程序选项孕几种不同的优化选项,在使用前应理解各优化选项的含义,然后选用最合适弋。通常情况下一旦选用最高级优化,编译程序会近乎病态地追求代码优化,芦的正确性,导致程序运行出错。因此应熟悉所使用的编译器,应知道哪些参芝到影响,哪些参数不会受到影响。有“。£店曲”和“EnableCodeCompression”两个优化选项。VR中,“Tiny%fsmall”两种内存模式。7种不同的内存模式选项。优化选项更多,一不小心更容易选到不恰当的选项。匕算法和数据结构普言,知道各种算法的优缺点,具体资料请参见相应的参考资料,有很多计算机召。将比较慢的顺序查找法用较快的二分查找或乱序查找法代替插入排序目快速排序、合并排序或根排序代替,都可以大

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论