写作初衷
进公司几个月了,还是码了不少代码,干了不少打杂的工作,所以编写的程序也是五花八门,有底层的驱动,完全用C实现的,开发环境主要是keil;也有上层工具的开发,MFC实现,开发环境是VS2008。自己在这些不同的项目中反复转换,同时又需要在各项目中和其他同事交叉合作,这里面就出现了很多的问题。
1)项目中怎么去和其他同事配合以提高项目的开发效率
2)项目多了怎样来管理自己的代码,能够让它在以后类似的项目中可以复用
3)对于不同的项目怎么来编写代码才会让人觉得你看起来还比较“专业”
我们喜欢按自己的风格做事,而且有些习惯还难以纠正,我们总觉得看别人的代码就很不舒服,甚至有时候不愿意使用别人已有的代码而宁愿自己重新写一个,确实有些人写出来的代码让人很DT,但是也许别人也认为你的代码也写得不咋样。这些问题其实都可以通过制定一个合理且符合常规的程序编写规范来解决,这里并不是要让每个人的风格都一样,但是要让人家觉得你码出来的东西不是“shit”而更愿意表扬你:“吖,小Y,你的代码写得不错嘛。”
其实真正的规范本身就不合理而且也相当的繁琐,我在这里只是泛泛而谈,普及一些常识性的基础而已,还需要在不断的经验积累中调整修改、加以完善。自己水平有限,还希望大家能够不吝赐教。
嵌入式C编程规则
说规则之前,我不得先给大家推荐一些好书,按照下面这个流程走一走,你会得到很快的提升(如果你爱她你就当然愿意为她付出自己的青春与money——我说的是编程)。好,从基础的说起,C经典国内版——谭浩强的“C语言程序设计”或者“The C Programming Language”。你不要说,切,老子在大一就学了谭浩强这本书了,看这个有个鸟用啊?我只想说你真的很装逼,你能完全搞懂上面的东西吗?数组指针、函数指针、结构体指针、文件操作……你都掌握了吗?其实把这本书或者电纸书常备,有空的时候就翻一翻,有问题的时候就查一查还是非常有用的,就像我们小学的时候经常使用的“新华字典”。有一定基础之后我们迫切的要多学习点C中最经典的部分——就是各种指针,这时“C和指针”这本书完全可以帮到你,“程序员面试宝典”这本书也可以让你明白很多的,上面那些都搞得差不多的时候就可以看一些进阶的书籍了,如果往嵌入式走推荐看“系统程序员成长计划”,往C++走看“Thinking in C++”都是些好书啊,哥表示我爱不释手。有了扎实的基础知识当然我们还需要良好的编程习惯和编程风格,推荐大家看看“高质量C++_C编程指南”。
好,下面就来说一些关于嵌入式编程中的一些规则和细节问题。我还是以最基础的IDE——keil来说吧,以后你用到的那些开发ARM和DSP的其实也都差不多。
文件准备
在嵌入式编程中,定义好工程中的一些规范是比较重要的,这样可以有效的管理项目文件,方便更新代码和合作调试。下面以keil中的工程文件为例说明。
1.keil中工程文件构成
有的人在使用keil创建工程时,把各种源文件,头文件都放在工程的目录下,然后加上编译、链接等生成的各种文件,让整个工程文件看起来非常的杂乱,这样对于代码的移植和管理非常不利。下面介绍一种我个人认为比较合理的keil工程结构。如图1所示:
图1 keil工程文件结构
2. 设置方法
其中“lis”和“obj”文件夹是用来存放编译后生成的“.lis”和“.obj”文件的,这个在新建工程的时候先在项目文件夹中新建这两个文件夹,然后进入keil的“option”中手动设置,如图2,选“Output”选择“Select Folder ForObjects”然后选到要目标文件夹。同样方法设置“lis”文件输出文件夹(上面那栏选“Listing”然后就相同了)。
图2 设置工程文件输出目录
图1中的“src”文件夹用来存放各种代码文件,打开后结构如图3所示。“tool”文件夹用来放工程依赖的一些工具如芯片仿真器的驱动,二进制文件生成器等。
“src”中包含有:“drv”用来放模块驱动的“.c”源文件,“inc”用来放“.h”文件,“lib”用来存放库文件,“main”用来放主程序代码。如果平时喜欢整理,可以将各个模块能够正确运行的程序做成一个一个的“demo”程序,这些demo程序就可以存放在一个“demo”文件中方便自己以后使用。
通过上面的方法来管理工程就使整个工程文件结构比较清晰,而且有个好处就是下次你直接把那些文件夹copy到新的工程中再添加进新工程直接使用就OK了。同样的,我们需要在keil软件中也建立相应的文件结构,如图4所示,这样在工程中能够比较容易的定位到你的模块代码。
图3 “src”文件夹的结构
图4 keil工程中的文件结构
类型定义
嵌入式c程序使用好typedef是比较重要的,在项目工程中应该添加一个属于自己的类型定义文件”typedef.h”头文件,该文件中将一些常用的类型使用typedef定义好。这样经过重新定义类型后在其他源程序中使得自己定义的类型关键字,就会使得程序看起来更规整,更简洁,我的“typedef.h”文件见附录B,仅供大家参考。
如:
typedef unsigned char UINT8;
typedef unsigned char U8;
typedef unsigned int UINT16;
typedef int INT16;
typedef int N16;
命名规则
下面开始介绍我们在编程时候的一些命名规则,这一点相当重要,这体现了一个程序员的专业程度,好的命名规则让我们的程序看起来就有美感or艺术。
共性规则:
1. 标识符的长度应当符合“min-length && max-information”原则,适当使用缩写来减少标识符长度,编程中常用的单词缩写整理见后面的附录A。
如:maximalValue—maxVal
2. 标识符的命名规则尽量与所采用的操作系统或开发工具的风格保持一致。
Windows采用的是“大小写”混排的格式,如“SetValue”。而Unix采用“小写加下划线”的方式,如“set_value”。在相应的开发环境下应该遵循开发环境的风格。
3. 用正确的反义词组命名具有互斥意义的变量或相反动作的函数等
如:
int minValue;
int maxValue;
void SetVal(int val);
int GetVal();
常量
使用宏定义#define或者const来定义常量,常量全部用大写单词,中间加下划线分隔。
如:
#define MAX_NUM 100
const unsigned int BUF_SIZE = 100;
变量命名:
1.程序中不要出现标识符完全相同的局部变量和全局变量。
如:
int time;
void Function(void)
{
int time;
}
2.变量的名字应当使用“名词”或者“形容词+名词”。
如:
单纯变量名用“小写名词表示”
int value;
char name[20];
有特殊意义的变量使用“形容词+名词”,形容词小写,名词大写以突出变量核心意思。
int oldValue;
函数命名
函数命名应该采用“动词”或者“动词+名词”(动宾词组)。在嵌入式C中,可以在函数前面加一个前缀,这样可以比较清楚的看出这个函数的返回值类型,在纯的C编程下,特别是在嵌入式的软件项目中,函数的返回值很重要,因为会load进开发板或者芯片中,有时候返回值的错误使用会带来难以预料的后果。所以以这种命名方式来编程可以让我们很快知道这个函数是有返回值的,而且返回值的类型也很清楚,使用的时候也会小心。
如:
void vSetVal(int val);
UINT8 ucGetLen();
常用前缀及意思:
v—void
unsigned char—uc,
char ch
int—n
好,嘎然而止。周末在公司整理的的这篇文章,想把它发出来,刚开始只想写一个命名规则来着,结果搞了这么多,再铺展下去就没完没了了,先这样吧,以后有了再补充。
Visual C++/MFC环境下的编程规则
现在还有很多人搞不懂C++、VC、VS、MFC、这些名词的关系和区别,那我就来普及下哈。C++是编程语言,C++包含了C语言的特性,C是C++的一个子集。而VC和VS呢,主要是用来说IDE(集成开发环境)的,VC一般情况下就特指Visual C++6.0这个经典的IDE,VS意思是Visual studio,是VC的升级后的IDE,如现在使用较多的VS2008/VS2010等。MFC——Microsoft Foundation Class即微软在提供的基础类库。我们在VC/VS中利用MFC来开发应用程序(如窗口应用程序)是很方便的。在Win32控制台的项目工程中,对于初学者来说,一般就是编写一些教科书式的程序,多数是拿来练手的。其实在win32环境中也可以做一些很高级的应用编程。而MFC应用程序编程就能做那种可以看得清楚,有菜单,有鼠标操作的程序了。
关于C++编程的书籍很多,根据本人的经验来看,还是应该从基础做起,先看谭浩强的“C++程序设计”,不要来不来就整个什么“C++ Primer”、“C++编程思想”之类的。你又要说了,谭浩强给了你多少好处,这儿又给他打广告!亲,好的东西其实广告并不重要,人家确实写的书很实在也确实是好书,人家不缺这基本销量增加的收入。关于应用程序的编程还是推荐大家先看孙鑫的“VC++深入详解”视频和那本“VC++深入详解”的配套课本,很详细也很基础,你依葫芦画瓢就可以很快学会了,其基础类参考书如“VisualC++2008入门经典”、“Beginning VisualC++2010”也不错。
当我们熟练了基础之后,就可以进阶了,“大象Thinking in UML”这本书可以让你学习到软件开发的规划和流程那些重要知识。还有一本经典的书就是“大话设计模式”,这本小说式的技术书写的真的很好啊,其他的如“敏捷软件开发”、“设计模式:Java语言中的应用”、“UNIX编程艺术”,都是好书,学了这些你感觉你顿时就上了一个新的台阶了。有人会说,尼玛,老子编C++的程序你让我看JAVA,UNIX搞毛啊,我只能说目前你还没那个境界,无法领会,不想跟你瞎扯淡那么多道理。
同样的,我们在使用微软提供的IDE建立工程的时候也要管理好自己的文件,因为做一个大的工程的话,里面的各种程序文件、库文件、资源文件等就更多了,我们还是要分们别类的在建立工程的时候就分好,方便我们以后管理,当然也方便自己把程序移植到其他的工程项目当中。这个现在暂时不贴图了,公司上不了QQ截图困难。以后补充上嘛。
好了,直接说Visual C++/MFC命名规则。
类型定义
这个在微软的IDE下就不需要你自己去搞类型定义了,这么强大的IDE还有啥子没给你准备好呢,你直接用可以了。说这个就顺便提一个工具“VisualAssist”,这个工具很“imba”啊,简直就像给你装了个编程外挂那么过瘾,直接装在了IDE里面,打开工程就可以用,不信你可以去试试。
VC中的命名规则
常量:和C一样,也使用#define或者const来定义常量,但是在C++中最好还是使用const来定义,因为const定义的常量有类型,使用的时候更安全。
规则:常量全部用大写单词,中间加下划线分隔。
如:
#define MAX_NUM 100
const unsigned int BUF_SIZE = 100;
变量:
在C++中定义变量可以和C有区别来定义,因为在C++中,变量的类型更加丰富,在变量的最好加上变量类型标识前缀,前缀均采用小写,整体结构采用“前缀+首字母大写单词(词组)”。
如:
INT nNum;
String strDispInfo;
CString strDispInfo;
Handle hWin;
常用的前缀和定义有
n/i——int,l——long,uc——unsigned char,ch——char,str——String or CString,h——handle,tag——结构体变量,c——Class,b——bool,g——global,dw——double word(双字)
……暂时记得这么多,以后补上其他的
局部变量
局部变量的定义如在函数中定义的变量,函数的参数这些变量,就直接采用全小写来表示,以区别于其他类型的变量定义。
如
Void SetVal(int val)
{
int temp = val;
}
C++结构体:
结构体命名采用“全大写”以示和类的区别,大写字母中间采用下划线划分单词。结构体中申明变量的规则就和C的变量命名规则相似,采用“小写开头单词+大写突出中心意思的单词”个人认为如果没有特别需要就不要在结构体中定义函数了,因为在C++中结构体其实就是类,用法也和类相同。C++中定义结构体主要用来把具有相同属性变量归类到一个组中,这样结构显得更加清晰。
Struct USER_INFO
{
int studentNum;
char studentName[20];
};
定义的结构体变量要命名时要加上前缀“tag”
如:
USER_INFO tagUsrInfo;
C++类:
定义类采用,“C+首字母大写”,即要在类名前加大写的“C”,表示这个是一个类的定义。在内中定义变量时都要加上前缀“m_”,表示该变量时类的成员变量。
如
Class CDispString
{
USER_INFO m_tagStudent;//类中定义结构体
CString m_strDispString;
UINT m_nLineNum;
Void Display(CString str);
};
实例化类的对象——即定义对象(说得更通俗点就是定义类变量)要在对象前加上前缀“c”
如
CDispString cDisplay;
在MFC中编程时,我们会制作一些窗口,添加一些资源,窗口中会用到各种控件,我们在给窗口以及窗口的控件添加更改ID的时候也有以下的一些规则。同时,在为这些控件以及资源添加变量的时候也要在变量中体现出这个变量时属于某个控件的。
VC资源名字定义格式:
菜单: IDM_XX //M:Menu
位图: IDB_XX //B:Bitmap
对话框: IDD_XX //D:Dialog
字符串: IDS_XX //S:String
ICON: IDI_XX //I:Icon
按钮控件: IDC_BTN_XX //BTN:Button
编辑控件: IDC_EDT_XX //EDT:EditBox
列表控件: IDC_LST_XX //LST:ListCtrl
树表控件: IDC_TRE_XX //TRE:TreeCtrl
富文本控件: IDC_RCH_XX //RCH:RichEdit
静态本控件: IDC_STT_XX //STT:StaticText
组合框控件: IDC_CMB_XX //CMB:ComboBox
滚动条控件: IDC_SCR_XX //SCR:ScrollBar
滑动条控件: IDC_SLD_XX //SLD:Slider
多选项控件: IDC_CHK_XX //CHK:CheckBox
单选项控件: IDC_RDB_XX //RDB:RadioButton
后话
写完这么多,还是比较麻烦,这个也只能算是一个初版,以后还会不断的修正,增加一些内容。我想说的是,既然你选择了这个行业,就要热爱他,也要按照行业的一些规则来做事,良好的编程习惯、编程风格和制作方案文档、项目管理等都需要不断的学习中间的业务知识,这样一步步的积累才能成为一名合格的高素质的“程序员”,一名让老板看重的好员工。当你把自己的工作当做一门艺术,你就会发现它是多么的迷人。
附录A 编程常用单词缩写
A:
array—ary,average—avg,
B:
buffer—buf,
C:
control—ctrl,count—cnt,
D:
data—dat,destination—dst,document—doc,display—disp,delete—del,
E:
edit—edt,error—err,escape—esc,
F:
function—func,
G:
grid—grd,
H:
I:
initial—init,image—img,library—lib,insert—ins,interrupt—int,information—info,
L:
label—lab,length—len,list—lst,
M:
Message—msg ,maximal—max,minim—min
N:
number—num,
O:
object—obj,
P:
password—pwd,picture—pic,position—pos,program—prg,point/pointer—pt,
S:
source—src,string—str,summation—sum,
T:
text—txt,
V:
Value—val,
W:
window—wnd,
附录B typedef.h类型定义文件
还有一种用小写定义的,个人觉得那样不安全,因为命名规则中我们将一般变量用小写来表示,不小心会造成名字一样的错误。
/**********************************************
***********************************************/
#ifndef _TYPEDEFINE_H_
#define _TYPEDEFINE_H_
/*******************定义数据类型*********************/
/************char***********/
typedef char INT8;
typedef unsigned char UCHAR;
typedef unsigned char UINT8;
typedef unsigned char U8;
typedef unsigned char BYTE;
typedef unsigned char BOOL;
/*************int***********/
typedef int INT16;
typedef int N16;
typedef unsigned int UINT;
typedef unsigned int UINT16;
typedef unsigned int WORD;
/************long**********/
typedef long INT32;
typedef unsigned long UINT32;
typedef unsigned long DWORD;
/***************************************************/
/***************定义通用宏**************************/
#define DISCOMPILE 0
#define ENCOMPILE 1
#define TURE 1
#define FALSE 0
#define OK 1
#define ERROR 0
#define MAX(x,y) (((x)>(y)) ? (x) : (y))
#define MIN(x,y) (((x)>(y)) ? (y) : (x))
/**************************************************/
#endif