嵌入式C编程的风格规范
一、概述
本文档描述在嵌入式开发中,C语言编程中应该注意的编程风格;力图使不同的模块,
不同人员编写的程序具有类似的风格,为程序方便维护打下基础。
针对人员:所有参与C编程的开发人员。
二、文件组织和结构
1.1 文件组织
一般在设计时就确定了系统的模块,并注重确定每个模块的接口部分,每个模块
我们用两个文件编写:.H和.C。
.H是模块的接口部分,只允许放置:
1)本模块公开的函数声明;
2)本模块公开的全局变量声明;
3)本模块公开的数据结构定义(即别的模块可能用到的struct);
4)本模块公开的宏定义;在其他模块中可能要引用的宏,如CHANNLE_MAXCOUNT;
5)其他的所有本模块的局部模块变量,模块内部函数不允许在.H中声明;
.C是模块的实现部分,可以自由定义:
1)本模块所需的模块变量;
2)仅供本模块使用的局部模块函数;如果觉得可以作为必要的函数库,可以单独
写个模块,使其成为公用的函数库;
3).H中声明函数的实现部分;
1.2 文件结构
每个.C文件分下面几个部分组成:
1)版权说明,文件说明;格式如下例:
/*
* comm.c This module implements the serial communication, include
* above layer 's bussiness
*
* Version: @(#)comm.c 1.0.1.1 2005-3-19
*
* Authors: VictorPANG, <shenglipang@163.com>
*
* Fixes:
* VictorPANG : Refix it. 2005-4-6
* WangJianFeng: Fill the file. 2005-4-6
* VictorPANG : Create the file but not fill it. 2005-03-19.
*/
2)include部分
//includes...
//-----------
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "com.h"
#include "mcu.h"
首先包含标准库头文件,用尖括号包含<>;
空行后再写本工程的头文件,用双引号包含"";
3)const部分
定义本文件需要的常量和宏,格式如下:
//consts...
//---------
const int PHONE_MAXCOUNT = 128;
#define READ_1302(reg) *((unsigned char xdata *)0x8000+reg)
注意:常量定义可以在使用前才定义,可能的话集中放置于此,如果方便可以
使用前才定义。
4)数据结构定义部分
定义本模块使用的数据结构,如:
typedef struct hub_macframe
{
uchar channelid;
union{
uint beginpos1;
uchar memindex1;
}u1;
union{
uint endpos1;
uint length1;
}u2;
//frame header
uchar sourceadd;
uchar destadd;
uchar headchk;
uchar chkcorrect;
struct hub_macframe xdata *next;
//use to indicate it's parent,when insert into send list,
//if insert method is copy, we increase frame's ref,and set new
//frame's parent to its parent
struct hub_macframe xdata *parent;
#define beginpos u1.beginpos1
#define memindex u1.memindex1
#define endpos u2.endpos1
#define length u2.length1
}hub_macframe;
注意:我们提倡使用数据结构(struct)组织关系紧密的各种数据,不提倡用
零散的变量表示事物;往往一个事物可以用一个struct可以表示他的所有属性。
5)模块变量定义部分
在定义了数据结构后,可以在本部分定义模块中需要的全局变量。如:
//global values...
//----------------
objectpool data hub_framepool;
5)模块私有函数定义部分
本部分定义只有本模块调用的函数,称为模块私有函数。
6)模块接口函数实现部分
本部分定义(实现).H中声明的接口函数。
三、标识符
标识符是文件名、变量名、常量名、函数名、数组名、子程序名、类型名等用户定义的
名称的总称。
我们约定以下几点:
1)变量名、函数名、数组名、子程序名一律用小写字母命名;常量名尽量用大写字母命名;
2)名称的选择。模块确定后它内部的函数名、子程序名、模块(全局)变量的命名均为
模块名_标识符。如com_send_message,com_receive_data,com_entity等。
对模块内函数中的局部变量的命名,不做要求。
3)标识符应该能正确表达它的含义,杜绝全局变量中使用i,j等没有任何含义的名称。
4)标识符不必太长,如果太短表达不清,可以适当加长,并用下划线分割各个单词,如:
com_send_message, phone_query_channel_state(char chnid)等。
四、注释
可以视情况编写注释,但要求模块的接口部分必须有注释。
注释一般在所注释对象的前面或并行部分。
到底使用//和/* */不做要求。
五、视觉组织
5.1 代码行
规则如下:
1)一行代码只做一件事情,如只定义一个变量,或只写一条语句。这样的代码容易
阅读,并且方便于写注释。
2)if、for、while、do等语句自占一行,执行语句不得紧跟其后。不论执行语句有
多少都要加{}(即使只有一行也要加上)。这样可以防止书写失误。
5.2 空格
规则如下:
1)关键字之后要留空格。象const、virtual、inline、case 等关键字之后至少要留
一个空格,否则无法辨析关键字。象if、for、while等关键字之后应留一个空格再
跟左括号'(',以突出关键字。
2)函数名之后不要留空格,紧跟左括号'(',以与关键字区别。
3)'('向后紧跟,')'、','、';'向前紧跟,紧跟处不留空格。
4)','之后要留空格,如Function(x, y, z)。如果';'不是一行的结束符号,其后要
留空格,如for (initialization; condition; update)。
5)赋值操作符、比较操作符、算术操作符、逻辑操作符、位域操作符,如"="、"+="
">="、"<="、"+"、"*"、"%"、"&&"、"||"、"<<","^"等二元操作符的前后应当加
空格。
6)一元操作符如"!"、"~"、"++"、"--"、"&"(地址运算符)等前后不加空格。
7)象"[]"、"."、"->"这类操作符前后不加空格。
8)对于表达式比较长的for语句和if语句,为了紧凑起见可以适当地去掉一些空格,
如for (i=0; i<10; i++)和if ((a<=b) && (c<=d))。
5.3 空行
空行起着分隔程序段落的作用。空行得体(不过多也不过少)将使程序的布局更加清晰。
空行不会浪费内存,虽然打印含有空行的程序是会多消耗一些纸张,但是值得。所以不
要舍不得用空行。
规则如下:
1)在每个类、结构体声明之后、每个函数定义结束之后都要加空行。
如:函数间的空行。
// 空行
void Function1(…)
{
…
}
// 空行
void Function2(…)
{
…
}
// 空行
void Function3(…)
{
…
}
2)在一个函数体内,逻辑上密切相关的语句之间不加空行,其它地方应加空行分隔。
如:函数内部的空行。
// 空行
while (condition)
{
statement1;
// 空行
if (condition)
{
statement2;
}
else
{
statement3;
}
// 空行
statement4;
}
5.4 缩进
规则如下:
1)程序的分界符'{'和'}'应独占一行并且位于同一列,同时与引用它们的语句左对齐。
2){ }之内的代码块在'{'右边数格处左对齐。我们规定用Tab键对齐,一个Tab键为4个
空格宽度。
嵌套的{},则使用缩进对齐,如:
{
…
{
…
}
…
}
-------------------------------------------------------------
| 修改人 | 修改时间 | 版本 | 修改项 |
-------------------------------------------------------------
| VictorPANG | 2005-4-6 | V1.0.1.1 | 创建、编写 |
-------------------------------------------------------------