实现C语言高效编程的四大秘技
副标题#e#
引言:
编写高效简捷的C语言代码,是很多软件工程师追求的方针。本文就事情中的一些体会和履历做相关的叙述,差池的处所请列位指教。
第1招:以空间换时间
计较机措施中最大的抵牾是空间和时间的抵牾,那么,从这个角度出发逆向思维来思量措施的效率问题,我们就有了办理问题的第1招——以空间换时间。
譬喻:字符串的赋值。
要领A,凡是的步伐:
#define LEN 32
char string1 [LEN];
memset (string1,0,LEN);
strcpy (string1,“This is a example!!”);
要领B:
const char string2[LEN] =“This is a example!”;
char * cp;
cp = string2 ;
(利用的时候可以直接用指针来操纵。)
从上面的例子可以看出,A和B的效率是不能比的。在同样的存储空间下,B直接利用指针就可以操纵了,而A需要挪用两个字符函数才气完成。B的缺点在于机动性没有A好。在需要频繁变动一个字符串内容的时候,A具有更好的机动性;假如回收要领B,则需要预存很多字符串,固然占用了大量的内存,可是得到了措施执行的高效率。
假如系统的及时性要求很高,内存尚有一些,那我推荐你利用该招数。
该招数的变招——利用宏函数而不是函数。举譬喻下:
要领C:
#define bwMCDR2_ADDRESS 4
#define bsMCDR2_ADDRESS 17
int BIT_MASK(int __bf)
{
return ((1U << (bw ## __bf)) - 1) << (bs ## __bf);
}
void SET_BITS(int __dst, int __bf, int __val)
{
__dst = ((__dst) & ~(BIT_MASK(__bf))) | \(((__val) << (bs ## __bf)) & (BIT_MASK(__bf))))
}
SET_BITS(MCDR2, MCDR2_ADDRESS, RegisterNumber);
要领D:
#p#副标题#e#
#define bwMCDR2_ADDRESS 4
#define bsMCDR2_ADDRESS 17
#define bmMCDR2_ADDRESS BIT_MASK(MCDR2_ADDRESS)
#define BIT_MASK(__bf) (((1U << (bw ## __bf)) - 1) << (bs ## __bf))
#define SET_BITS(__dst, __bf, __val) \
((__dst) = ((__dst) & ~(BIT_MASK(__bf))) | \
(((__val) << (bs ## __bf)) & (BIT_MASK(__bf))))
SET_BITS(MCDR2, MCDR2_ADDRESS, RegisterNumber);
函数和宏函数的区别就在于,宏函数占用了大量的空间,而函数占用了时间。各人要知道的是,函数挪用是要利用系统的栈来生存数据的,假如编译器里有栈查抄选项,一般在函数的头会嵌入一些汇编语句对当前栈举办查抄;同时,CPU也要在函数挪用时生存和规复当前的现场,举办压栈和弹栈操纵,所以,函数挪用需要一些CPU时间。而宏函数不存在这个问题。宏函数仅仅作为预先写好的代码嵌入到当前措施,不会发生函数挪用,所以仅仅是占用了空间,在频繁挪用同一个宏函数的时候,该现象尤其突出。 D要领是我看到的最好的置位操纵函数,是ARM公司源码的一部门,在短短的三行内实现了许多成果,险些涵盖了所有的位操纵成果。C要领是其变体,个中滋味还需各人仔细体会。
第2招:数学要领办理问题
此刻我们演绎高效C语言编写的第二招——回收数学要领来办理问题。
数学是计较机之母,没有数学的依据和基本,就没有计较机的成长,所以在编写措施的时候,回收一些数学要了解对措施的执行效率有数量级的提高。
举譬喻下,求 1~100的和。
要领E
int I , j;
for (I = 1 ;I<=100; I ++){
j += I;
}
要领F
int I;
I = (100 * (1+100)) / 2
这个例子是我印象最深的一个数学用例,是我的计较机启蒙老师考我的。其时我只有小学三年级,惋惜我其时不知道用公式 N×(N+1)/ 2 来办理这个问题。要领E轮回了100次才办理问题,也就是说最罕用了100个赋值,100个判定,200个加法(I和j);而要领F仅仅用了1个加法,1 次乘法,1次除法。结果自然不问可知。所以,此刻我在编措施的时候,更多的是动头脑找纪律,最大限度地发挥数学的威力来提高措施运行的效率。 第3招:利用位操纵
第3招:利用位操纵,淘汰除法和取模的运算
在计较机措施中,数据的位是可以操纵的最小数据单元,理论上可以用“位运算”来完成所有的运算和操纵。一般的位操纵是用来节制硬件的,可能做数据调动利用,可是,机动的位操纵可以有效地提高措施运行的效率。举譬喻下:
要领G
int I,J;
I = 257 /8;
J = 456 % 32;
要领H
int I,J;
I = 257 >>3;
J = 456 - (456 >> 4 << 4);
#p#分页标题#e#
在字面上仿佛H比G贫苦了许多几何,可是,仔细查察发生的汇编代码就会大白,要领G挪用了根基的取模函数和除法函数,既有函数挪用,尚有许多汇编代码和寄存器参加运算;而要领H则仅仅是几句相关的汇编,代码更简捷,效率更高。虽然,由于编译器的差异,大概效率的差距不大,可是,以我今朝碰着的MS C ,ARM C 来看,效率的差距照旧不小。相关汇编代码就不在这里罗列了。
运用这招需要留意的是,因为CPU的差异而发生的问题。好比说,在PC上用这招编写的措施,并在PC上调试通过,在移植到一个16位机平台上的时候,大概会发生代码隐患。所以只有在必然技能进阶的基本下才可以利用这招。
第4招:汇编嵌入
高效C语言编程的必杀技,第四招——嵌入汇编。
“在熟悉汇编语言的人眼里,C语言编写的措施都是垃圾”。这种说法固然过火了一些,可是却有它的原理。汇编语言是效率最高的计较机语言,可是,不行能靠着它来写一个操纵系统吧?所以,为了得到措施的高效率,我们只好回收变通的要领 ——嵌入汇编,殽杂编程。
举譬喻下,将数组一赋值给数组二,要求每一字节都相符。
char string1[1024],string2[1024];
要领I
int I;
for (I =0 ;I<1024;I++)
*(string2 + I) = *(string1 + I)
要领J
#ifdef _PC_
int I;
for (I =0 ;I<1024;I++)
*(string2 + I) = *(string1 + I);
#else
#ifdef _ARM_
__asm
{
MOV R0,string1
MOV R1,string2
MOV R2,#0
loop:
LDMIA R0!, [R3-R11]
STMIA R1!, [R3-R11]
ADD R2,R2,#8
CMP R2, #400
BNE loop
}
#endif
要领I是最常见的要领,利用了1024次轮回;要领J则按照平台差异做了区分,在ARM平台下,用嵌入汇编仅用128次轮回就完成了同样的操纵。这里有伴侣会说,为什么不消尺度的内存拷贝函数呢?这是因为在源数据里大概含有数据为0的字节,这样的话,尺度库函数会提前竣事而不会完成我们要求的操纵。这个例程典范应用于LCD数据的拷贝进程。按照差异的CPU,纯熟利用相应的嵌入汇编,可以大大提高措施执行的效率。
固然是必杀技,可是假如等闲利用会支付惨重的价钱。这是因为,利用了嵌入汇编,便限制了措施的可移植性,使措施在差异平台移植的进程中,卧虎藏龙,险象环生!同时该招数也与现代软件工程的思想相违背,只有在迫不得已的环境下才可以回收。切记,切记。