您好,欢迎访问三七文档
当前位置:首页 > 商业/管理/HR > 咨询培训 > 嵌入式C语言进阶之道
嵌入式C进阶之道版本:V1.0瓶盖水羽哥(蝈蝈)2010-8-31(发布)前言C语言的书有一大堆,嵌入C语言的书也不少,但都不过是简单介绍一下标准C语言的语法,再讲一下嵌入式C语言与标准C的区别,讲一下新增加的关键字。这样的书,对于初学者或许是适合的。问题是,若是我不愿意只是当一个小菜鸟,我想对嵌入式C语言有更多更深的了解时,我突然发现,满图书馆的书,竟找不到一本,能解我心头之惑。对于在实际工作当中,你不再是独自编写程序,你要和小组内的成员之间分工合作,你要学会模块化编程、要写出更规范更安全的代码、做更合理的优化、减少更多的bug。所有的这些,都迫使你必须更彻底的理解嵌入式C的语法结构,数据细节,与硬件打交道的特性,使得你必须时时考虑硬件与C的对应关系并养成良好的编程习惯。本文的原意是想尽可能多的解决上述问题,帮助更多的新人深入理解嵌入式C语言。本文是我工作之余整理而来。是对我个人学习嵌入式C语言过程的总结。本文涉及的知识点多数来自于网络,其中加入我个人理解以及自己平时遇到的注意点。本文从编程风格谈起,讲述了模块化的编程方法,对一些大型项目中常用重点关键字做了讲解,参照MISRAC2004规范,对嵌入式C安全编程做了阐述,对一些嵌入式C的小技巧进行了讨论。在读本文时,我假设你有C语言基础、至少理解一种微控制器(51、PIC、AVR、DSP、ARM等)、有简单的(这里本想写较深的)汇编基础。声明:本人不拥有该文档的版权,任何人可随意传播。本人不对文中任何事物负责,(呵呵,工作比较忙,交流尽量通过邮箱),但会不定期发布新版本以改正前版的不足。希望本文能帮助一些热爱嵌入式编程的新人们,所以,如果您有更好的建议、发现本文档的错误,请将以上详细信息发到我邮箱,我会在新版本后面,注明您的名字(或者网名)。希望广大的嵌入式爱好者们能共同努力,为后来者们铺一个更平坦的大道。我的邮箱:zhzhchang@126.com技术博客:瓶盖水羽哥2010-7-9养成良好的编程风格1/7一.良好的编程风格编程的总则:编程首要是要考虑程序的可行性,然后是可读性、可移植性、健壮性以及可测试性。大多数程序员只是关注程序的可行性,而忽略了可读性,可移植性和健壮性,其实我个人认为,程序的可行性和健壮性与程序的可读性有很大的关系,能写出可读性很好的程序的程序员,他写的程序的可行性和健壮性必然不会差,也会有不错的可移植性.程序的可读性需要程序员有一个良好的编程风格.好风格应该成为一种习惯。如果你在开始写代码时就关心风格问题,如果你花时间去审视和改进它,你将会逐渐养成一种好的编程习惯。一旦这种习惯变成自动的东西,你的潜意识就会帮你照料许多细节问题,甚至你在工作压力下写出的代码也会更好。1.排版a.代码缩进空格数为4个。若是可能,尽量用空格来代替Tab键,因为有些编译器不支持Tab键(我自己至今未见过,但确实有这个风险),这给程序的移植带来了问题。在keil中这个问题很容易解决,只需在在keil主界面的菜单栏点击Edit—Configuration…,弹出Configuration窗口,点击Editor标签,在其中C/C++File:、ASM、OtherFiles栏下,选中Insertspacesfortab:复选框,Tab对应的框中填4,这样按tab键就相当于按下四个空格键。BOOLBufClr(UINT8*dest,UINT32size){if(NULL==dest||NULL==size){returnFALSE;}}b.较长的语句要分2行来书写,并用‘\’符号隔开。uncrc=calcCRC16(Packet.p,unlen);if((UINT8)uncrc!=Packet.down_ser.mCrc[0]\||(UINT8)(uncrc8)!=Packet.down_ser.mCrc[1]){BELL(ON);}c.函数代码的参数过长,分多行来书写。voidUARTSendAndRecv(UINT8*ucSendBuf,UINT8ucSendLength,UINT8*ucRecvBuf,UINT8ucRecvLength){……}d.if、do、while、switch、for、case、default等关键字,必须加上大括号{}。if(bSendEnd){BELL(ON);养成良好的编程风格2/7}else{BELL(OFF);}//--------------------------for(i=0;iucRecvLength;i++){ucRecvBuf[i]=i;}//--------------------------switch(ucintStatus){caseUSB_INT_EP2_OUT:{USBCiEP2Send(USBMainBuf,ucrecvLen);USBCiEP1Send(USBMainBuf,ucrecvLen);}break;caseUSB_INT_EP2_IN:{USBCiWriteSingleCmd(CMD_UNLOCK_USB);}break;……}2.注释a.边写代码边注释,修改代码同时修改相应的注释,以保证注释与代码的一致性。不再有用的注释要删除。注释应当准确、易懂,防止注释有二义性。错误的注释不但无益反而有害。尽量避免在注释中使用缩写,特别是不常用缩写。注释的位置应与被描述的代码相邻,可以放在代码的上方或右方,不可放在下方。b.说明性文件必选在文件头着重说明,例如*.c、*.h文件/****************************************************************************定时器+计数器测频**文件:frequency.c*作者:小瓶盖*说明:定时器+计数机测频率*编写时间:2010.3.17*版本:1.0*修改日期:无养成良好的编程风格3/7*---------------------------------------------------------------------------*注:本程序定义6个数码管,经过实测,在200HZ~50KHZ时结果较准确,误差小于0.4%,*50KHZ以上频率未进行测量.据资料表明,可以测量到120KHZ,本程序未证明.*****************************************************************************/#includexxxx.hvoidfunc(void){}c.函数头应该进行注释,例如函数名称、输入参数、返回值、功能说明。/**************将所有参数写入AT24C64,共4字节**********************说明:将表号和用户电量共四字节数据写入AT24C64中*入口参数:*1.数据间接寻址地址-buf*2.写入到AT24C64的地址字-addh,addrl*3.写入字节数-count*出口参数:1表示写成功,0表示写失败***************************************************************/bitwrite_byte(unsignedchar*buf,unsignedcharaddrh,unsignedcharaddrl,unsignedcharcount){……}d.全局变量要注释其功能,若为关键的局部变量同样需要注释其功能。volatileUINT8__ucSysMsg=SYS_IDLE;voidSYSSetMsgPriority(void){SYSMSGMsgt;//临时存储消息UINT8i;}e.复杂的宏定义同样要加上注释。/*SYS_MSG_MAP建立一个消息映射宏参数NAME:消息映射表的名字宏参数NUM_OF_MSG:消息映射的个数*/#defineSYS_MSG_MAP(NAME,NUM_OF_MSG)do\{\DEFINE_MSG_NAME((NAME));\UINT8i;\for(i=0;iNUM_OF_MSG;i++)\{\ININ_CUR_MSG(i)\}\养成良好的编程风格4/7}while(0)f.复杂的结构体同样要加上注释。/*奇偶校验结构体*/typedefstruct_PKT_PARITY{UINT8m_ucHead1;//首部1UINT8m_ucHead2;//首部2UINT8m_ucOptCode;//操作码UINT8m_ucDataLength;//数据长度UINT8m_szDataBuf[16];//数据UINT8m_ucParity;//奇偶校验值}PKT_PARITY;g.相对独立的语句组注释。对这一组语句做特别说明,写在语句组上侧,和此语句组之间不留空行,与当前语句组的缩进一致。注意,说明语句组的注释一定要写在语句组上面,不能写在语句组下面。3.标识符a.变量的命名方法一:采用匈牙利命名法。命名规则的主要思想是“在变量中加入前缀以增进人们对程序的理解”。例如平时声明32位整型变量Length对应使用匈牙利命名法为unLength。现在列出经常用到的变量类型。变量类型示例charcLengthunsignedcharucLengthshortintsLengthunsignedshortintusLengthintnLengthunsignedintunLengthchar*szBufunsignedchar*uszBufvolatileunsignedchar__ucLength方法二:局部变量以小写字母命名;全局变量以首字母大写方式命名(骆驼式);定义类型和宏定义常数以大写字母命名;变量的作用域越大,它的名字所带有的信息就应该越多。局部变量:intstudent_age;全局变量:intStudentAge;宏定义常数:#defineSTUDENT_NUM10类型定义:typedefINT16Sint;(我个人喜欢第二种方法)b.变量命名要注意缩写而且让人简单易懂,若是特别缩写要详细说明。经常用到的缩写如:养成良好的编程风格5/7Count可缩写为CntMessage可缩写为MsgPacket可缩写为PktTemp可缩写为Tmp平时不经常用到的缩写,要注释:SerialCommunication可缩写为SrlComm//串口通信变量SerialCommunicationStatus可缩写为SrlCommStat//串口通信状态变量c.全局变量和全局函数的命名一定要详细,不惜多用几个单词,例如函数UARTPrintfStringForLCD,因为它们在整个项目的许多源文件中都会用到,必须让使用者明确这个变量或函数是干什么用的。局部变量和只在一个源文件中调用的内部函数的命名可以。简略一些,但不能太短,不要使用单个字母做变量名,只有一个例外:用i、j、k做循环变量是可以的。d.用于编译开关的文件头,必须加上当前文件名称,防止编译时产生冲突。例如在UARTInterface.h头文件中,必须加上以下内容#ifndef__UARTINTERFACE_H__#define__UARTINTERFACE_H__externvoidUARTPrintfString(CONSTINT8*str);externvoidUARTSendNBytes(UINT8*ucSendBytes,UINT8ucLen);……//其他外部声明的代码#endife.禁止用汉语拼音作为标识符名称,可读性极差。呵呵。f.建议名称间的区别要显而易见。使用标识符名称要注意的一个相关问题是发生在名称之间只有一个字符或少数字符不同的情况,特别是名称比较长时,当名称间的区别很容易被误读时问题就比较显著,比如1(数字1)和l(L的小写)、0和O、2和Z、5和S,或者n和h。4.表达式和基本语句a.不要编写太复杂的复合表达式;例如:i=a=b&&cd
本文标题:嵌入式C语言进阶之道
链接地址:https://www.777doc.com/doc-5398679 .html