一段完美的代码不仅在于找到一个给定的问题的解决方案,但在它的简单性,有效性,紧凑性和效率(内存)。设计的代码比实际执行更难。因此,每一个程序员当用C语言开发时,都应该保持这些基本的东西在头脑中。本文向你介绍规范你的C代码的几种方法。 1、在可能的情况下使用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都是整数的指针。 2、在一个逻辑条件语句中常数项永远在左侧。 int x = 4; if (x = 1) { x = x + 2; printf("%d",x);// Output is 3 } int x = 4; if (1 = x) { x = x + 2; printf("%d",x); // Compilation error } 使用"="赋值运算符,替代"=="相等运算符,这是个常见的输入错误。常数项放在左侧,将产生一个编译时错误,让你轻松捕获你的错误。注:"="是赋值运算符。b = 1会设置变量b等于值1。"=="相等运算符。如果左侧等于右侧,返回true,否则返回false。 3、确保声明和定义是静态的,除非您希望从不同的文件中调用该函数。 在同一文件函数对其他函数可见,才称之为静态函数。它限制其他访问内部函数,如果我们希望从外界隐藏该函数。现在我们并不需要为内部函数创建头文件,其他看不到该函数。静态声明一个函数的优点包括: (1)两个或两个以上具有相同名称的静态函数,可用于在不同的文件。 (2)编译消耗减少,因为没有外部符号处理。 4、节约内存(内存对齐和填充的概念) 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个字节) 5、使用无符号整数,而不是整数的,如果你知道的值将永远是否定的。 有些处理器可以处理无符号的整数,比有符号整数的运算速度要快。(这也是很好的实践,帮助self-documenting代码) 6、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()](); 7、全局变量。使用全局变量比向函数传递参数更加有效率,这样做去除了函数调用前参数入栈和函数完成后参数出栈的需要。当然,使用全局变量会对程序有一些负作用。使用全局变量比函数传递参数更加有效率。这样做去除了函数调用参数入栈和函数完成后参数出栈所需要的时间。然而决定使用全局变量会影响程序的模块化和重入,故要慎重使用。 8、嵌入式系统编程应避免使用标准库例程,因为很多大的库例程设法处理所有可能的情况,所以占用了庞大的内存空间,因而应尽可能地减少使用标准库例程。 9、Inline函数。在C++中,关键字Inline可以被加入到任何函数的声明中。这个关键字请求编译器用函数内部的代码替换所有对于指出的函数的调用。这样做在两个方面快于函数调用。这样做在两个方面快于函数调用:第一,省去了调用指令需要的执行时间;第二,省去了传递变元和传递过程需要的时间。但是使用这种方法在优化程序速度的同时,程序长度变大了,因此需要更多的ROM。使用这种优化在Inline函数频繁调用并且只包含几行代码的时候是最有效的。 10、用指针代替数组。在许多种情况下,可以用指针运算代替数组索引,这样做常常能产生又快又短的代码。与数组索引相比,指针一般能使代码速度更快,占用空间更少。使用多维数组时差异更明显。下面的代码作用是相同的,但是效率不一样。 数组索引 指针运算 For(;;){ p=array A=array[t++]; for(;;){ a=*(p++); ...... ...... } 指针方法的优点是,array的地址每次装入地址p后,在每次循环中只需对p增量操作。在数组索引方法中,每次循环中都必须进行基于t值求数组下标的复杂运算。 11、不定义不使用的返回值。function函数定义并不知道函数返回值是否被使用,假如返回值从来不会被用到,应该使用void来明确声明函数不返回任何值。 12、手动编写汇编。在嵌入式软件开发中,一些软件模块最好用汇编语言来写,这可以使程序更加有效。虽然C/C++编译器对代码进行了优化,但是适当的使用内联汇编指令可以有效的提高整个系统运行的效率。 13、使用寄存器变量。在声明局部变量的时候可以使用register关键字。这就使得编译器把变量放入一个多用途的寄存器中,而不是在堆栈中,合理使用这种方法可以提高执行速度。函数调用越是频繁,越是可能提高代码的速度。 14、使用增量和减量操作符。在使用到加一和减一操作时尽量使用增量和减量操作符,因为增量符语句比赋值语句更快,原因在于对大多数CPU来说,对内存字的增、减量操作不必明显地使用取内存和写内存的指令,比如下面这条语句:x=x+1; 模仿大多数微机汇编语言为例,产生的代码类似于: move A,x ;把x从内存取出存入累加A add A,1 ;累加器A加1 store x ;把新值存回x 如果使用增量操作符,生成的代码下: incr x ;x加1 显然,不用取指令和存指令,增、减量操作执行的速度加快,同时长度也缩短了。