C语言提高代码效率的几种方法
一段完美的代码不仅在于找到一个给定的问题的解决方案,但在它的简单性,有效性,紧凑性和效率(内存)。设计的代码比实际执行更难。因此,每一个程序员当用C语言开发时,都应该保持这些基本的东西在头脑中。本文向你介绍规范你的C代码的几种方法。
、在可能的情况下使用typedef替代macro.当然有时候你无法避免macro,但是typedef更好。
typedef int* INT_PTR; INT_PTR a ,b;
# define INT_PTR int*; INT_PTR a ,b;
在这个宏定义中,a是一个指向整数的指针,而b是只有一个整数声明。使用typedef a和b都是整数的指针。
、在一个逻辑条件语句中常数项永远在左侧。
int x = ; if (x = )
{
x = x + ;
printf("%d",x);// Output is 3 }
int x = ;
if ( = x)
{
x = x + ;
printf("%d",x); // Compilation error
}
使用"="赋值运算符,替代"=="相等运算符,这是个常见的输入错误。常数项放在左侧,将产生一个编译时错误,让你轻松捕获你的错误。注:"="是赋值运算符。b = 1会设置变量b等于值1。"=="相等运算符。如果左侧等于右侧,返回true,否则返回false。
、确保声明和定义是静态的,除非您希望从不同的文件中调用该函数。
在同一文件函数对其他函数可见,才称之为静态函数。它限制其他访问内部函数,如果我们希望从外界隐藏该函数。现在我们并不需要为内部函数创建头文件,其他看不到该函数。静态声明一个函数的优点包括:
()两个或两个以上具有相同名称的静态函数,可用于在不同的文件。
()编译消耗减少,因为没有外部符号处理。
、节约内存(内存对齐和填充的概念)
struct { char c; int i;
short s;}str_1;
struct { char c; shorts; inti;}str_2;
假设一个字符需要1个字节,short占用2个字节和int需要4字节的内存。起初,我们会认为上面定义的结构是相同的,因此占据相同数量的内存。然而,而str_1占用12个字节,第二个结构只需要8个字节?这怎么可能呢?
请注意,在第一个结构,3个不同的4个字节被分配到三种数据类型,而在第二个结构的前4个自己char和short可以被采用,int可以采纳在第二个的4个字节边界(一共8个字节)
、使用无符号整数,而不是整数的,如果你知道的值将永远是否定的。
有些处理器可以处理无符号的整数,比有符号整数的运算速度要快。(这也是很好的实践,帮助self-documenting代码)
、switch-case语句。在程序中经常会使用switch-case语句,每一个由机器语言实现的测试和跳转仅仅是为了决定下一步要做什么,就浪费了处理器时间。为了提高速度,可以把具体的情况按照它们发生的相对频率排序。即把最可能发生的情况放在第一,最不可能发生的情况放在最后,这样会减少平均的代码执行时间。
当switch语句中的case标号很多时,为了减少比较的次数,明智的做法是把大switch语句转为嵌套switch语句。把发生频率高的case标号放在一个switch语句中,并且是嵌套switch语句的最外层,发生相对频率相对低的case标号放在另一个switch语句中。比如,下面的程序段把相对发生频率低的情况放在缺省的case标号内。
pMsg=ReceiveMessage();
switch (pMsg->type)
{
case FREQUENT_MSG1:
handleFrequentMsg();
break;
case FREQUENT_MSG2:
handleFrequentMsg2();
break;
......
case FREQUENT_MSGn:
handleFrequentMsgn();
break;
default: //嵌套部分用来处理不经常发生的消息
switch (pMsg->type)
{
case INFREQUENT_MSG1:
handleInfrequentMsg1();
break;
case INFREQUENT_MSG2:
handleInfrequentMsg2();
break;
......
case INFREQUENT_MSGm:
handleInfrequentMsgm();
break;
}
}
如果switch中每一种情况下都有很多的工作要做,那么把整个switch语句用一个指向函数指针的表来替换会更加有效,比如下面的switch语句,有三种情况:
enum MsgType{Msg1, Msg2, Msg3}
switch (ReceiveMessage())
{
case Msg1;......
case Msg2;.....
case Msg3;.....
}
为了提高执行速度,用下面这段代码来替换这个上面的switch语句
/*准备工作*/
int handleMsg1(void);
int handleMsg2(void);
int handleMsg3(void);
/*创建一个函数指针数组*/
int (*MsgFunction [])()={handleMsg1, handleMsg2, handleMsg3};
/*用下面这行更有效的代码来替换switch语句*/
status=MsgFunction[ReceiveMessage()]();
、全局变量。使用全局变量比向函数传递参数更加有效率,这样做去除了函数调用前参数入栈和函数完成后参数出栈的需要。当然,使用全局变量会对程序有一些负作用。使用全局变量比函数传递参数更加有效率。这样做去除了函数调用参数入栈和函数完成后参数出栈所需要的时间。然而决定使用全局变量会影响程序的模块化和重入,故要慎重使用。
、嵌入式系统编程应避免使用标准库例程,因为很多大的库例程设法处理所有可能的情况,所以占用了庞大的内存空间,因而应尽可能地减少使用标准库例程。
、Inline函数。在C++中,关键字Inline可以被加入到任何函数的声明中。这个关键字请求编译器用函数内部的代码替换所有对于指出的函数的调用。这样做在两个方面快于函数调用。这样做在两个方面快于函数调用:第一,省去了调用指令需要的执行时间;第二,省去了传递变元和传递过程需要的时间。但是使用这种方法在优化程序速度的同时,程序长度变大了,因此需要更多的ROM。使用这种优化在Inline函数频繁调用并且只包含几行代码的时候是最有效的。
、用指针代替数组。在许多种情况下,可以用指针运算代替数组索引,这样做常常能产生又快又短的代码。与数组索引相比,指针一般能使代码速度更快,占用空间更少。使用多维数组时差异更明显。下面的代码作用是相同的,但是效率不一样。
数组索引 指针运算
For(;;){ p=array
A=array[t++]; for(;;){
a=*(p++);
...... ......
}
指针方法的优点是,array的地址每次装入地址p后,在每次循环中只需对p增量操作。在数组索引方法中,每次循环中都必须进行基于t值求数组下标的复杂运算。
、不定义不使用的返回值。function函数定义并不知道函数返回值是否被使用,假如返回值从来不会被用到,应该使用void来明确声明函数不返回任何值。
、手动编写汇编。在嵌入式软件开发中,一些软件模块最好用汇编语言来写,这可以使程序更加有效。虽然C/C++编译器对代码进行了优化,但是适当的使用内联汇编指令可以有效的提高整个系统运行的效率。
、使用寄存器变量。在声明局部变量的时候可以使用register关键字。这就使得编译器把变量放入一个多用途的寄存器中,而不是在堆栈中,合理使用这种方法可以提高执行速度。函数调用越是频繁,越是可能提高代码的速度。
、使用增量和减量操作符。在使用到加一和减一操作时尽量使用增量和减量操作符,因为增量符语句比赋值语句更快,原因在于对大多数CPU来说,对内存字的增、减量操作不必明显地使用取内存和写内存的指令,比如下面这条语句:x=x+;
模仿大多数微机汇编语言为例,产生的代码类似于:
move A,x ;把x从内存取出存入累加A
add A, ;累加器A加1
store x ;把新值存回x
如果使用增量操作符,生成的代码下:
incr x ;x加1
显然,不用取指令和存指令,增、减量操作执行的速度加快,同时长度也缩短了。
C语言提高代码效率的几种方法的更多相关文章
- SQL Server 提高执行效率的16种方法
1.尽量不要在where中包含子查询; 关于时间的查询,尽量不要写成:where to_char(dif_date,'yyyy-mm-dd')=to_char('2007-07-01′,'yyyy-m ...
- 提高SQL查询效率的30种方法
转载:提高SQL查询效率的30种方法 内容摘录如下: 1.对查询进行优化,应尽量避免全表扫描,首先应考虑在 where 及 order by 涉及的列上建立索引. 2.应尽量避免在 where 子句中 ...
- 改善C#程序,提高程序运行效率的50种方法
改善C#程序,提高程序运行效率的50种方法 转自:http://blog.sina.com.cn/s/blog_6f7a7fb501017p8a.html 一.用属性代替可访问的字段 1..NET ...
- oracle提高查询效率的34条方法
注:本文来源:远方的守望者 <oracle提高查询效率的34条方法> oracle提高查询效率的34条方法 1.选择最有效率的表名顺序 (只在基于规则的优化器中有效): ORACLE的解 ...
- C语言清空输入缓冲区的N种方法对比
转自C语言清空输入缓冲区的N种方法对比 C语言中有几个基本输入函数: //获取字符系列 int fgetc(FILE *stream); int getc(FILE *stream); int get ...
- R语言中样本平衡的几种方法
R语言中样本平衡的几种方法 在对不平衡的分类数据集进行建模时,机器学习算法可能并不稳定,其预测结果甚至可能是有偏的,而预测精度此时也变得带有误导性.在不平衡的数据中,任一算法都没法从样本量少的类中获取 ...
- 编写Java程序_输入三个整数x,y,z,请把这三个数由小到大输出,请写出实现代码。(3种方法)
要求说明: 输入三个整数x,y,z,请把这三个数由小到大输出. 实现代码: 第1种方法: import java.util.Scanner; public class xyzMaxMin{ publi ...
- 前端程序员的蜕变——JS的 event 对象属性、使用实例、兼容性处理(极大提高代码效率、减少代码量)
下面讨论一下 js 中的 Event 对象,主要从以下三个方面详细的描述(点击标题可跳转到对应部分): 1.什么是event 2.怎么用event,用他该注意什么,几个简单实际应用 3.event在不 ...
- 提升Python编程效率的几种方法
前言 我们知道Python这门语言在运行速度上已经败给了许多别的语言(比如C, C++, Java, Golang....).但从一个开发者的角度来看Python是我最喜欢的语言,很大一部分原因在于其 ...
随机推荐
- Page (computer memory)
A page, memory page, or virtual page is a fixed-length contiguous block of virtual memory, described ...
- Problem binding to [bigdata-server-01:9000] java.net.BindException: Cannot assign requested address;
If the port is "0", then the OS is looking for any free port -so the port-in-use and port- ...
- 传递一个父id返回所有子id的用法,可用于删除父级以下的所有子级
先在common文件夹建立一个function.php文件,然后写一个递归函数,传递一个父id返回所有子id,如下: function getChildrenId($node,$pid){ $arr= ...
- SQL Server 2005中top关键字的用法
1.返回N条记录数 select top n * from <表名> [查询条件] 2.返回总结果集中指定百分比记录数 select top n percent * from <表名 ...
- OpenMeetings安装
OpenMeetings是一个开源的视频会议软件. 它是基于OpenLaszlo’s的新流媒体格式和开源的Flash服务器---Red5! 采用了flash流媒体服务器Red5+OpenMeeting ...
- linux host=${host:-"localhost"}使用方法
localhost=${host:-"localhost"} host 变量未设定或者为空,host取"-"后面的值;否则host=$host host=${h ...
- linux内核段属性机制【转】
本文转载自:https://github.com/TongxinV/oneBook/issues/9 linux内核段属性机制 以subsys_initcall和module_init为例 subsy ...
- Consul环境搭建
大家在玩的时候 一定要使用ningx 1.9以上版本啊! 下载:wget https://releases.hashicorp.com/consul/0.7.5/consul_0.7.5_linux_ ...
- OC-内存管理的所有权链问题
背景: 最近维护之前的项目,没有注意具体的对象之间的关系,导致了一个bug. 让我了解到对象的所有权链问题. 需要内存管理的知识: 众所周知,oc是使用引用计数来管理内存的(当一个对象被持有,他的re ...
- BZOJ_3781_小B的询问_莫队
BZOJ_3781_小B的询问_莫队 Description 小B有一个序列,包含N个1~K之间的整数.他一共有M个询问,每个询问给定一个区间[L..R],求Sigma(c(i)^2)的值,其中i的值 ...