1. switch-case与if-else
switch-case的效率比if-else的效率要高很多,属于典型的空间换时间问题。在编译的时候,会创建一个jump map存在于.rodata段中,运行的时候直接根据case值查表,找到对应的值,直接跳转到对应的地址。if-else需要遍历条件分支直到命中条件。
1. 1switch—case的优缺点
(1)switch case的优点:
当分支较多时,用switch的效率是很高的。因为switch是确定了选择值之后直接跳转到那个特定的分支.
(2)witch case的缺点:
1.switch...case占用较多的代码空间,因为它要生成跳表,特别是当case常量分布范围很大但实际有效值又比较少的情况,switch...case的空间利用率将变得很低。
2.switch...case只能处理case为常量的情况。一般为字符常量或者数字类型的变量,局限性比较大。
1.2. if-else的优缺点
(1)if else的优点:if else能应用于更多的场景,更加灵活。
(2)if else的缺点:if else必须遍历所以得可能值,执行效率比较低。
2. 指针问题
从上面的例子可以看出,A和B的效率是不能比的。在同样的存储空间下,B直接使用指针就可以操作了,而A需要调用两个字符函数才能完成。B的缺点在于灵活性没有A好。在需要频繁更改一个字符串内容的时候,A具有更好的灵活性;如果采用方法B,则需要预存许多字符串,虽然占用了大量的内存,但是获得了程序执行的高效率。如果系统的实时性要求很高,内存还有一些,那我推荐你使用该招数。
总结:核心思想其实是将需要用到的信息事先定义好,在使用的时候直接调用即可,字符串的赋值、数值的计算(查表)等等。
3. 宏和函数
方法1:
#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);
方法2:
#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时间。而宏函数不存在这个问题。宏函数仅仅作为预先写好的代码嵌入到当前程序,不会产生函数调用,所以仅仅是占用了空间,在频繁调用同一个宏函数的时候,该现象尤其突出。 方法2是我看到的最好的置位操作函数,是ARM公司源码的一部分,在短短的三行内实现了很多功能,几乎涵盖了所有的位操作功能。方法1是其变体,其中滋味还需大家仔细体会。
引申:
注意inline和define的区别
4 内联函数
内联是C++对函数的一种特殊修饰,实际上,内联函数可以更形象地被称为内嵌函数。当编译器编译程序时,如果发现某段代码调用的是一个内联函数,那么它就不再去调用该函数,而是将该函数的代码直接插入当前函数调用的位置,这样就省去了函数调用过程中的那些繁琐的幕后工作,提高了代码的执行效率,这样就以程序空间的增加换取了执行时间的减少。
内联函数的使用规则
1. 内联函数要短小精悍
内联函数的实质是将函数代码复制到函数调用的位置, 它的使用会增加程序的体积,所以内联函数应该尽量做到短小精悍,一般不要超过5行。如果将一个比较复杂的函数内联,往往会导致程序的体积迅速膨胀,最后往往得不偿失。
2. 内联函数执行的时间要短
内联函数不仅要短小,同时其执行时间也要短,这样才能体现内联函数的优势。如果函数执行的时间远大于函数调用过程中那些幕后工作所花费的时间,那么通过内联函数所节省下来的那一点点时间也就无足轻重了。
3. 内联函数应该是被重复多次调用的
内联函数每次调用节省下来的时间其实非常微小,只有当这些时间累积到一定程度后,它才具有实际的意义。如果一个内联函数只被调用过一次,那么它节省下来的那一点点时间是没有任何实际意义的,反倒是因为内联函数而增加了程序的体积。
4. inline关键字仅仅是一种建议
inline关键字仅仅是一种对编译器的建议,表明程序员对这个函数的处理意见。但是在某些特定的情况下,编译器将不理会inline关键字,而强制让函数成为普通函数。这时编译器会给出相应的警告消息。反过来,如果某个函数并没有加上inline修饰,但如果编译器在进行代码优化的时候,认为将这个函数内联会提高代码性能,也会自作主张地将其内联。所以,inline关键字只是表示我们建议编译器将函数内联处理,至于到底是否进行内联处理,最终还是要看编译器的脸色。
虽然内联函数可以在一定程度上提高应用程序的性能,但是它并不是解决性能问题的灵丹妙药,也并不是用得越多越好。很多时候,如果发现应用程序存在性能上的问题,更多地应该从应用程序的结构和设计上寻找问题的解决办法。内联函数,只是饭前的小甜点而已,偶尔尝一点还不错,但是并不能当饭吃。
表达式形式的宏定义一例:
#define ExpressionName(Var1,Var2) (Var1+Var2)*(Var1-Var2)
inline 推出的目的,也正是为了取代这种表达式形式的宏定义,它消除了它的缺点,同时又很好地继承了它的优点。inline代码放入预编译器符号表中,高效;它是个真正的函数,调用时有严格的参数检测;它也可作为类的成员函数。
#define 宏名要替换的代码
宏定义,保存在预编译器的符号表中,执行高效;作为一种简单的符号替换,不进行其中参数有效性的检测
typedef 已有类型 新类型
别名, 常用于创建平台无关类型, typedef 在编译时被解释,因此让编译器来应付超越预处理器能力的文本替换
网友评论