嵌入式C语言高级编程的技巧
C语言发明至今已经过去了60余年,但如今人们对它的讨论依然热度不减,C语言虽然入门简单,但是难在精通,下文将会针对C语言在嵌入式系统中运用的编程技巧给大家做些详解。
一:使用do{} while(0)封装宏
#define TEST do{
//宏定义
}while(0);
把宏定义封装起来,这样的好处是后面加分号不容易出错。
二:定长的类型
在C语言中,不同的操作系统,变量类型所占的字节数是不同的,我们不能一贯的用C语言的基本的变量类型去定义变量,这样在跨平台的时候,代码的通用性就会出现问题。
为了跨平台,很多系统定义了一套自己的类型,比如:
uint8_t //1个字节
uint16_t //2个字节
uint32_t //4个字节
uint64_t //8个字节
所以,我们在编程中应当多使用上述的类型,尽量少使用int 、long,这样能够保证我们的代码在不同的操作系统当中的通用性。
三:if判断的顺序颠倒
在写if判断条件的时候,我们往往把= =的符号写漏,导致判断错误,但是在查找bug的时候全很难发现问题所在,所以在写判断的时候,我们可以把判断条件反过来写,既:
if(x == 5)
{
//假如写漏了符号if(x = 5),编译器依然可以执行,但意思已经改变
}
我们可以写成:
if(5 == x)
{
//假如写漏了符号if(5 = x),编译器报错
}
这样的好处是,即便你写漏了符号,编译器会直接报错,因为变量不能给常量赋值。
四:算法优化
算法优化指对程序时空复杂度的优化:
在计算机上进行程序设计时一般不必过多关注程序代码的长短,只需考虑功能的实现,但嵌入式系统就必须考虑系统的硬件资源,在程序设计时,应尽量采用生成代码短的算法,在不影响程序功能实现的情况下优化算法。
五:循环运行效率
提高循环体效率的基本办法就是降低循环体的复杂性:
在嵌套循环语句中,应当把最长的循环放在最内层,最短的循环放在最外层。这样可以减少 CPU跨切循环的次数。
六:储存器分配
由于成本限制,嵌入式系统存储器容量有限。程序中所有的变量,包含的库函数以及堆栈等都使用有限的内存:全局变量在整个程序范围内都有效。
程序执行完后才会释放;静态变量的作用范围也是整个程序,只有局部变量中的动态变量在函数执行完后会释放。因此, 在程序中应尽量使用局部变量,提高内存使用效率。
程序中堆的大小受限于所有全局数据和栈空间都分配后的剩余量,如果堆太小,程序不能够在需要的时候分配内存。因此在使用 malloc 函数申请内存之后一定要用 free 函数进行释放, 防止内存泄露。
七:工程管理
在一个完整的项目中,除了代码功能的实现之外,工程的管理也尤为重要,一个好的工程项目,它的内部各项代码的条理都非常清晰,而不会把所有的函数或者功能都放在同一个c文件当中,适当的封装头文件,自己定义c文件,使自己的工程模块化,通用性有一个质的变化。
八:灵活运用extern和static关键字
extern是声明让别的文件中能够使用,static修饰之后的函数或全局变量不能被其他文件使用。
九:灵活使用void*
void*常常用于函数地封装比较多,当然也有用在其它地方,比如在结构体内定义void*类型的私有指针方便扩展结构体。我们平时在封装自己的函数时,也可以多考虑看看有没有必要使用void*使得函数地通用性更强一些。
十:使用宏给结构体初始化
如果频繁使用一个结构体的话,使用使用宏来给结构体进行赋值是很方便的一种做法。
#define NEW_RECT(length, width) {(length), (width)}
typedef struct _Rect
{
int length;
int width;
}Rect;
int main(void)
{
Rect rect = NEW_RECT(10, 5);
printf("rect length = %d, width = %d\n", rect.length, rect.width);
return 0;
}