一份不错的嵌入式C编码规范!
来源:嵌入式大杂烩发布时间:2023-07-031442浏览
询问 AI
编写代码时最重要的一条规则是:检查周围的代码并尝试模仿它。
作为维护人员,如果收到的补丁明显与周围代码的编码风格不同,这是令人沮丧的。这是不尊重人的,就像某人穿着泥泞的鞋子走进一间一尘不染的房子。
因此,无论本文推荐的是什么,如果已经编写了代码并且您正在对其进行修补,请保持其当前的样式一致,即使它不是您最喜欢的样式。
这里列出了最明显和最重要的一般规则。在你继续阅读其他章节之前,请仔细检查它们。
使用C99标准
不使用制表符,而是使用空格
每个缩进级别使用4个空格
在关键字和左括号之间使用一个空格
在函数名和左括号之间不要使用空格
int32_ta=sum(4,3);/*OK*/
int32_ta=sum(4,3);/*Wrong*/
不要在变量/函数/宏/类型中使用__或_前缀。这是为C语言本身保留的
对于严格的模块私有函数,使用prv_ name前缀
对于包含下划线_ char的变量/函数/宏/类型,只能使用小写字母
左花括号总是与关键字(for, while, do, switch, if,…)在同一行
size_ti;
for(i=0;i<5;++i){/*OK*/
}
for(i=0;i<5;++i){/*Wrong*/
}
for(i=0;i<5;++i)/*Wrong*/
{
}
- 在比较操作符和赋值操作符之前和之后使用单个空格
//微信公众号:嵌入式大杂烩
int32_ta;
a=3+4;/*OK*/
for(a=0;a<5;++a)/*OK*/
a=3+4;/*Wrong*/
a=3+4;/*Wrong*/
for(a=0;a<5;++a)/*Wrong*/
- 每个逗号后用单空格
//微信公众号:嵌入式大杂烩
func_name(5,4);/*OK*/
func_name(4,3);/*Wrong*/
- 不要初始化静态和全局变量为0(或NULL),让编译器为您做
staticint32_ta;/*OK*/
staticint32_tb=4;/*OK*/
staticint32_ta=0;/*Wrong*/
void
my_func(void){
staticint32_t*ptr;/*OK*/
staticcharabc=0;/*Wrong*/
}
- 在同一行中声明所有相同类型的局部变量
void
my_func(void){
chara;/*OK*/
charb;/*Wrong,variablewithchartypealreadyexists*/
chara,b;/*OK*/
}
- 按顺序声明局部变量
i.自定义结构和枚举
ii.整数类型,更宽的无符号类型优先
iii.单/双浮点
int
my_func(void){
/*1*/
my_struct_tmy;/*Firstcustomstructures*/
my_struct_ptr_t*p;/*Pointerstoo*/
/*2*/
uint32_ta;
int32_tb;
uint16_tc;
int16_tg;
charh;
/*...*/
/*3*/
doubled;
floatf;
}
- 总是在块的开头声明局部变量,在第一个可执行语句之前
- 在for循环中声明计数器变量
/*OK*/
for(size_ti=0;i<10;++i)
/*OK,ifyouneedcountervariablelater*/
size_ti;
for(i=0;i<10;++i){
if(...){
break;
}
}
if(i==10){
}
/*Wrong*/
size_ti;
for(i=0;i<10;++i)...
- 避免在声明中使用函数调用来赋值变量,除了单个变量
void
a(void){
/*Avoidfunctioncallswhendeclaringvariable*/
int32_ta,b=sum(1,2);
/*Usethis*/
int32_ta,b;
b=sum(1,2);
/*Thisisok*/
uint8_ta=3,b=4;
}
除了char、float或double之外,始终使用stdint.h标准库中声明的类型。例如,8位的uint8_t等
不要使用stdbool.h库。分别使用1或0表示真或假
/*OK*/
uint8_tstatus;
status=0;
/*Wrong*/
#include<stdbool.h>
boolstatus=true;
永远不要与真实相比较。例如,使用
if(check_func()){…}替换if (check_func() == 1)总是将指针与空值进行比较
void*ptr;
/*...*/
/*OK,compareagainstNULL*/
if(ptr==NULL||ptr!=NULL){
}
/*Wrong*/
if(ptr||!ptr){
}
- 总是使用前增量(和递减),而不是后增量(和递减)
int32_ta=0;
...
a++;/*Wrong*/
++a;/*OK*/
for(size_tj=0;j<10;++j){}/*OK*/
总是使用size_t作为长度或大小变量
如果函数不应该修改指针所指向的内存,则总是使用const作为指针
如果不应该修改函数的形参或变量,则总是使用const
/*Whendcouldbemodified,datapointedtobydcouldnotbemodified*/
void
my_func(constvoid*d){
}
/*Whendanddatapointedtobydbothcouldnotbemodified*/
void
my_func(constvoid*constd){
}
/*Notrequired,itisadvised*/
void
my_func(constsize_tlen){
}
/*Whendshouldnotbemodifiedinsidefunction,onlydatapointedtobydcouldbemodified*/
void
my_func(void*constd){
}
- 当函数可以接受任何类型的指针时,总是使用void *,不要使用uint8_t *。函数在实现时必须注意正确的类型转换
/*
*Tosenddata,functionshouldnotmodifymemorypointedtoby`data`variable
*thus`const`keywordisimportant
*
*Tosendgenericdata(ortowritethemtofile)
*anytypemaybepassedfordata,
*thususe`void*`
*/
/*OKexample*/
void
send_data(constvoid*data,size_tlen){/*OK*/
/*Donotcast`void*`or`constvoid*`*/
constuint8_t*d=data;/*Functionhandlespropertypeforinternalusage*/
}
void
send_data(constvoid*data,intlen){/*Wrong,notnotuseint*/
}
总是使用括号和sizeof操作符
不要使用变长数组。使用动态内存分配代替标准C malloc和自由函数,或者如果库/项目提供了自定义内存分配,使用它的实现
看看LwMEM,一个自定义内存管理库。
/*OK*/
#include<stdlib.h>
void
my_func(size_tsize){
int32_t*arr;
arr=malloc(sizeof(*arr)*n);/*OK,Allocatememory*/
arr=malloc(sizeof*arr*n);/*Wrong,bracketsforsizeofoperatoraremissing*/
if(arr==NULL){
/*FAIL,nomemory*/
}
free(arr);/*Freememoryafterusage*/
}
/*Wrong*/
void
my_func(size_tsize){
int32_tarr[size];/*Wrong,donotuseVLA*/
}
总是将variable与0进行比较,除非它被视为布尔类型
永远不要将布尔处理的变量与0或1进行比较。用NOT(!)代替
size_tlength=5;/*Countervariable*/
uint8_tis_ok=0;/*Boolean-treatedvariable*/
if(length)/*Wrong,lengthisnottreatedasboolean*/
if(length>0)/*OK,lengthistreatedascountervariablecontainingmultivalues,notonly0or1*/
if(length==0)/*OK,lengthistreatedascountervariablecontainingmultivalues,notonly0or1*/
if(is_ok)/*OK,variableistreatedasboolean*/
if(!is_ok)/*OK,-||-*/
if(is_ok==1)/*Wrong,nevercomparebooleanvariableagainst1!*/
if(is_ok==0)/*Wrong,use!fornegativecheck*/
- 对于注释,总是使用/* comment */,即使是单行注释
- 在头文件中总是包含带有extern关键字的c++检查
- 每个函数都必须包含doxygen-enabled注释,即使函数是静态的
- 使用英文名称/文本的函数,变量,注释
- 变量使用小写字母
- 如果变量包含多个名称,请使用下划线。force_redraw。不要使用forceRedraw
- 对于C标准库的包含文件,请始终使用<和>。例如,# include < stdlib.h >
- 对于自定义库,请始终使用""。例如,# include“my_library.h”
- 当转换为指针类型时,总是将星号与类型对齐,例如。uint8_t* t = (uint8_t*)var_width_diff_type
- 始终尊重项目或库中已经使用的代码风格
- 不允许以//开头的注释。总是使用/* comment */,即使是单行注释
//Thisiscomment(wrong)
/*Thisiscomment(ok)*/
- 对于多行注释,每行使用空格+星号
/*
*Thisismulti-linecomments,
*writtenin2lines(ok)
*/
/**
*Wrong,usedouble-asteriskonlyfordoxygendocumentation
*/
/*
*Singlelinecommentwithoutspacebeforeasterisk(wrong)
*/
/*
*Singlelinecommentinmulti-lineconfiguration(wrong)
*/
/*Singlelinecomment(ok)*/
- 注释时使用12个缩进(12 * 4个空格)偏移量。如果语句大于12个缩进,将注释4-空格对齐(下面的例子)到下一个可用缩进
void
my_func(void){
chara,b;
a=call_func_returning_char_a(a);/*Thisiscommentwith12*4spacesindentfrombeginningofline*/
b=call_func_returning_char_a_but_func_name_is_very_long(a);/*Thisiscomment,alignedto4-spacesindent*/
}
每个可以从模块外部访问的函数都必须包含函数原型(或声明)
函数名必须小写,可以用下划线_分隔
/*OK*/
voidmy_func(void);
voidmyfunc(void);
/*Wrong*/
voidMYFunc(void);
voidmyFunc();
- 当函数返回指针时,将星号对齐到返回类型
/*OK*/
constchar*my_func(void);
my_struct_t*my_func(int32_ta,int32_tb);
/*Wrong*/
constchar*my_func(void);
my_struct_t*my_func(void);
- 对齐所有的功能原型(使用相同/相似的功能)以提高可读性
/*OK,functionnamesaligned*/
voidset(int32_ta);
my_type_tget(void);
my_ptr_t*get_ptr(void);
/*Wrong*/
voidset(int32_ta);
constchar*get(void);
- 函数实现必须在单独的行中包含返回类型和可选的其他关键字
/*OK*/
int32_t
foo(void){
return0;
}
/*OK*/
staticconstchar*
get_string(void){
return"Helloworld!\r\n";
}
/*Wrong*/
int32_tfoo(void){
return0;
}
- 使变量名全部小写,下划线_字符可选
/*OK*/
int32_ta;
int32_tmy_var;
int32_tmyvar;
/*Wrong*/
int32_tA;
int32_tmyVar;
int32_tMYVar;
- 按类型将局部变量分组在一起
void
foo(void){
int32_ta,b;/*OK*/
chara;
charb;/*Wrong,chartypealreadyexists*/
}
- 不要在第一个可执行语句之后声明变量
void
foo(void){
int32_ta;
a=bar();
int32_tb;/*Wrong,thereisalreadyexecutablestatement*/
}
- 你可以在下一个缩进级别中声明新的变量
int32_ta,b;
a=foo();
if(a){
int32_tc,d;/*OK,canddareinif-statementscope*/
c=foo();
int32_te;/*Wrong,therewasalreadyexecutablestatementinsideblock*/
}
- 用星号声明指针变量与类型对齐
/*OK*/
char*a;
/*Wrong*/
char*a;
char*a;
- 当声明多个指针变量时,可以使用星号对变量名进行声明
/*OK*/
char*p,*n;
结构名或枚举名必须小写,单词之间有下划线_字符
结构或枚举可以包含typedef关键字
所有结构成员都必须小写
所有枚举成员必须是大写的
结构/枚举必须遵循doxygen文档语法
在声明结构体时,它可以使用以下三种不同的选项之一:
1、当结构体仅用名称声明时,它的名称后不能包含_t后缀。
structstruct_name{
char*a;
charb;
};
2、当只使用typedef声明结构时,它的名称后面必须包含_t后缀。
typedefstruct{
char*a;
charb;
}struct_name_t;
3、当结构用name和typedef声明时,它不能包含_t作为基本名称,它必须在它的名称后面包含_t后缀作为typedef部分。
typedefstructstruct_name{
char*a;
charb;
charc;
}struct_name_t;
错误声明的例子及其建议的纠正:
/*aandbmustbeseparatedto2lines*/
/*Nameofstructurewithtypedefmustinclude_tsuffix*/
typedefstruct{
int32_ta,b;
}a;
/*Correctedversion*/
typedefstruct{
int32_ta;
int32_tb;
}a_t;
/*Wrongname,itmustnotinclude_tsuffix*/
structname_t{
int32_ta;
int32_tb;
};
/*Wrongparameters,mustbealluppercase*/
typedefenum{
MY_ENUM_TESTA,
my_enum_testb,
}my_enum_t;
- 在声明时初始化结构时,使用C99初始化风格
/*OK*/
a_ta={
.a=4,
.b=5,
};
/*Wrong*/
a_ta={1,2};
- 当为函数句柄引入new typedef时,使用_fn后缀
/*Functionaccepts2parametersandreturnsuint8_t*/
/*Nameoftypedefhas`_fn`suffix*/
typedefuint8_t(*my_func_typedef_fn)(uint8_tp1,constchar*p2);
每个复合语句必须包括左花括号和右花括号,即使它只包含1个嵌套语句
每个复合语句必须包含单个缩进;嵌套语句时,每个嵌套包含1个缩进大小
/*OK*/
if(c){
do_a();
}else{
do_b();
}
/*Wrong*/
if(c)
do_a();
else
do_b();
/*Wrong*/
if(c)do_a();
elsedo_b();
- 在if或if-else-if语句的情况下,else必须与第一条语句的右括号在同一行
/*OK*/
if(a){
}elseif(b){
}else{
}
/*Wrong*/
if(a){
}
else{
}
/*Wrong*/
if(a){
}
else
{
}
- 在do-while语句的情况下,while部分必须与do部分的右括号在同一行
/*OK*/
do{
int32_ta;
a=do_a();
do_b(a);
}while(check());
/*Wrong*/
do
{
/*...*/
}while(check());
/*Wrong*/
do{
/*...*/
}
while(check());
- 每一个开括号都需要缩进
if(a){
do_a();
}else{
do_b();
if(c){
do_c();
}
}
- 不要做没有花括号的复合语句,即使是单个语句。下面的例子展示了一些不好的做法
if(a)do_b();
elsedo_c();
if(a)do_a();elsedo_b();
- 空while循环、do-while循环或for循环必须包含花括号
/*OK*/
while(is_register_bit_set()){}
/*Wrong*/
while(is_register_bit_set());
while(is_register_bit_set()){}
while(is_register_bit_set()){
}
- 如果while(或for、do-while等)为空(嵌入式编程中也可能是这种情况),请使用空的单行括号
/*Waitforbittobesetinembeddedhardwareunit
uint32_t*addr=HW_PERIPH_REGISTER_ADDR;
/*Waitbit13tobeready*/
while(*addr(1<<13)){}/*OK,emptyloopcontainsnospacesinsidecurlybrackets*/
while(*addr(1<<13)){}/*Wrong*/
while(*addr(1<<13)){/*Wrong*/
}
while(*addr(1<<13));/*Wrong,curlybracketsaremissing.Canleadtocompilerwarningsorunintentionalbugs*/
- 尽量避免在循环块内递增变量,参见示例
/*Notrecommended*/
int32_ta=0;
while(a<10){
.
..
...
++a;
}
/*Better*/
for(size_ta=0;a<10;++a){
}
/*Better,ifincmaynothappenineverycycle*/
for(size_ta=0;a<10;){
if(...){
++a;
}
}
- 为每个case语句添加单个缩进
- 使用额外的单缩进break语句在每个case或default
/*OK,everycasehassingleindent*/
/*OK,everybreakhasadditionalindent*/
switch(check()){
case0:
do_a();
break;
case1:
do_b();
break;
default:
break;
}
/*Wrong,caseindentmissing*/
switch(check()){
case0:
do_a();
break;
case1:
do_b();
break;
default:
break;
}
/*Wrong*/
switch(check()){
case0:
do_a();
break;/*Wrong,breakmusthaveindentasitisundercase*/
case1:
do_b();/*Wrong,indentundercaseismissing*/
break;
default:
break;
}
- 总是包含default语句
/*OK*/
switch(var){
case0:
do_job();
break;
default:break;
}
/*Wrong,defaultismissing*/
switch(var){
case0:
do_job();
break;
}
- 如果需要局部变量,则使用花括号并在里面放入break语句。将左花括号放在case语句的同一行
switch(a){
/*OK*/
case0:{
int32_ta,b;
charc;
a=5;
/*...*/
break;
}
/*Wrong*/
case1:
{
int32_ta;
break;
}
/*Wrong,breakshallbeinside*/
case2:{
int32_ta;
}
break;
}
- 总是使用宏而不是文字常量,特别是对于数字
- 所有的宏必须是全大写的,并带有下划线_字符(可选),除非它们被明确标记为function,将来可能会被常规函数语法替换
/*OK*/
#defineMY_MACRO(x)((x)*(x))
/*Wrong*/
#definesquare(x)((x)*(x))
- 总是用圆括号保护输入参数
/*OK*/
#defineMIN(x,y)((x)<(y)?(x):(y))
/*Wrong*/
#defineMIN(x,y)x<y?x:y
- 总是用括号保护最终的宏计算
/*Wrong*/
#defineMIN(x,y)(x)<(y)?(x):(y)
#defineSUM(x,y)(x)+(y)
/*ImagineresultofthisequationusingwrongSUMimplementation*/
int32_tx=5*SUM(3,4);/*Expectedresultis5*7=35*/
int32_tx=5*(3)+(4);/*Itisevaluatedtothis,finalresult=19whichisnotwhatweexpect*/
/*Correctimplementation*/
#defineMIN(x,y)((x)<(y)?(x):(y))
#defineSUM(x,y)((x)+(y))
- 当宏使用多个语句时,使用do-while(0)语句保护它
typedefstruct{
int32_tpx,py;
}point_t;
point_tp;/*Definenewpoint*/
/*Wrongimplementation*/
/*Definemacrotosetpoint*/
#defineSET_POINT(p,x,y)(p)->px=(x);(p)->py=(y)/*2statements.Lastoneshouldnotimplementsemicolon*/
SET_POINT(p,3,4);/*Setpointtoposition3,4.Thisevaluatesto...*/
(p)->px=(3);(p)->py=(4);/*...tothis.Inthisexamplethisisnotaproblem.*/
/*Considerthisuglycode,howeveritisvalidbyCstandard(notrecommended)*/
if(a)/*Ifaistrue*/
if(b)/*Ifbistrue*/
SET_POINT(p,3,4);/*Setpointtox=3,y=4*/
else
SET_POINT(p,5,6);/*Setpointtox=5,y=6*/
/*Evaluatestocodebelow.Doyouseetheproblem?*/
if(a)
if(b)
(p)->px=(3);(p)->py=(4);
else
(p)->px=(5);(p)->py=(6);
/*Orifwerewriteitalittle*/
if(a)
if(b)
(p)->px=(3);
(p)->py=(4);
else
(p)->px=(5);
(p)->py=(6);
/*
*Askyourselfaquestion:Towhich`if`statement`else`keywordbelongs?
*
*Basedonfirstpartofcode,answerisstraight-forward.Toinner`if`statementwhenwecheck`b`condition
*Actualanswer:Compilationerroras`else`belongsnowhere
*/
/*Betterandcorrectimplementationofmacro*/
#defineSET_POINT(p,x,y)do{(p)->px=(x);(p)->py=(y);}while(0)/*2statements.Nosemicolonafterwhileloop*/
/*Orevenbetter*/
#defineSET_POINT(p,x,y)do{\/*Backslashindicatesstatementcontinuesinnewline*/
(p)->px=(x);\
(p)->py=(y);\
}while(0)/*2statements.Nosemicolonafterwhileloop*/
/*Noworiginalcodeevaluatesto*/
if(a)
if(b)
do{(p)->px=(3);(p)->py=(4);}while(0);
else
do{(p)->px=(5);(p)->py=(6);}while(0);
/*Everypartof`if`or`else`containsonly`1`innerstatement(do-while),hencethisisvalidevaluation*/
/*Tomakecodeperfect,usebracketsforeveryif-ifelse-elsestatements*/
if(a){/*Ifaistrue*/
if(b){/*Ifbistrue*/
SET_POINT(p,3,4);/*Setpointtox=3,y=4*/
}else{
SET_POINT(p,5,6);/*Setpointtox=5,y=6*/
}
}
- 不缩进子语句内#if语句
/*OK*/
#ifdefined(XYZ)
#ifdefined(ABC)
/*dowhenABCdefined*/
#endif/*defined(ABC)*/
#else/*defined(XYZ)*/
/*DowhenXYZnotdefined*/
#endif/*!defined(XYZ)*/
/*Wrong*/
#ifdefined(XYZ)
#ifdefined(ABC)
/*dowhenABCdefined*/
#endif/*defined(ABC)*/
#else/*defined(XYZ)*/
/*DowhenXYZnotdefined*/
#endif/*!defined(XYZ)*/
文档化的代码允许doxygen解析和通用的html/pdf/latex输出,因此正确地执行是非常重要的。
- 对变量、函数和结构/枚举使用doxygen支持的文档样式
- 经常使用\作为doxygen,不要使用@
- 始终使用5x4空格(5个制表符)作为文本行开始的偏移量
/**
*\briefHoldspointertofirstentryinlinkedlist
*Beginningofthistextis5tabs(20spaces)frombeginningofline
*/
static
type_t*list;
- 每个结构/枚举成员都必须包含文档
- 注释的开头使用12x4空格偏移量
/**
*\briefThisispointstruct
*\noteThisstructureisusedtocalculateallpoint
*relatedstuff
*/
typedefstruct{
int32_tx;/*!<PointXcoordinate*/
int32_ty;/*!<PointYcoordinate*/
int32_tsize;/*!<Pointsize.
Sincecommentisverybig,
youmaygotonextline*/
}point_t;
/**
*\briefPointcolorenumeration
*/
typedefenum{
COLOR_RED,/*!<Redcolor.Thiscommenthas12x4
spacesoffsetfrombeginningofline*/
COLOR_GREEN,/*!<Greencolor*/
COLOR_BLUE,/*!<Bluecolor*/
}point_color_t;
函数的文档必须在函数实现中编写(通常是源文件)
函数必须包括简要和所有参数文档
如果每个参数分别为in或out输入和输出,则必须注意
如果函数返回某个值,则必须包含返回形参。这不适用于void函数
函数可以包含其他doxygen关键字,如note或warning
在参数名和描述之间使用冒号:
/**
*\briefSum`2`numbers
*\param[in]a:Firstnumber
*\param[in]b:Secondnumber
*\returnSumofinputvalues
*/
int32_t
sum(int32_ta,int32_tb){
returna+b;
}
/**
*\briefSum`2`numbersandwriteittopointer
*\noteThisfunctiondoesnotreturnvalue,itstoresittopointerinstead
*\param[in]a:Firstnumber
*\param[in]b:Secondnumber
*\param[out]result:Outputvariableusedtosaveresult
*/
void
void_sum(int32_ta,int32_tb,int32_t*result){
*result=a+b;
}
- 如果函数返回枚举的成员,则使用ref关键字指定哪个成员
/**
*\briefMyenumeration
*/
typedefenum{
MY_ERR,/*!<Errorvalue*/
MY_OK/*!<OKvalue*/
}my_enum_t;
/**
*\briefChecksomevalue
*\return\refMY_OKonsuccess,memberof\refmy_enum_totherwise
*/
my_enum_t
check_value(void){
returnMY_OK;
}
- 对常量或数字使用符号(' NULL ' => NULL)
/**
*\briefGetdatafrominputarray
*\param[in]in:Inputdata
*\returnPointertooutputdataonsuccess,`NULL`otherwise
*/
constvoid*
get_data(constvoid*in){
returnin;
}
- 宏的文档必须包括hideinitializer doxygen命令
/**
*\briefGetminimalvaluebetween`x`and`y`
*\param[in]x:Firstvalue
*\param[in]y:Secondvalue
*\returnMinimalvaluebetween`x`and`y`
*\hideinitializer
*/
#defineMIN(x,y)((x)<(y)?(x):(y))
在文件末尾留下一个空行
每个文件都必须包括文件的doxygen注释和后跟空行的简要描述(使用doxygen时)
/**
*\filetemplate.h
*\briefTemplateincludefile
*/
/*Hereisemptyline*/
每个文件(头文件或源文件)必须包含许可证(开始注释包括单个星号,因为doxygen必须忽略这个)
使用与项目/库已经使用的相同的许可证
/**
*\filetemplate.h
*\briefTemplateincludefile
*/
/*
*Copyright(c)yearFirstNameLASTNAME
*
*Permissionisherebygranted,freeofcharge,toanyperson
*obtainingacopyofthissoftwareandassociateddocumentation
*files(the"Software"),todealintheSoftwarewithoutrestriction,
*includingwithoutlimitationtherightstouse,copy,modify,merge,
*publish,distribute,sublicense,and/orsellcopiesoftheSoftware,
*andtopermitpersonstowhomtheSoftwareisfurnishedtodoso,
*subjecttothefollowingconditions:
*
*Theabovecopyrightnoticeandthispermissionnoticeshallbe
*includedinallcopiesorsubstantialportionsoftheSoftware.
*
*THESOFTWAREISPROVIDED"ASIS",WITHOUTWARRANTYOFANYKIND,
*EXPRESSORIMPLIED,INCLUDINGBUTNOTLIMITEDTOTHEWARRANTIES
*OFMERCHANTABILITY,FITNESSFORAPARTICULARPURPOSE
*ANDNONINFRINGEMENT.INNOEVENTSHALLTHEAUTHORSORCOPYRIGHT
*HOLDERSBELIABLEFORANYCLAIM,DAMAGESOROTHERLIABILITY,
*WHETHERINANACTIONOFCONTRACT,TORTOROTHERWISE,ARISING
*FROM,OUTOFORINCONNECTIONWITHTHESOFTWAREORTHEUSEOR
*OTHERDEALINGSINTHESOFTWARE.
*
*Thisfileispartoflibrary_name.
*
*Author:FirstNameLASTNAME<optional_email@example.com>
*/
头文件必须包含保护符#ifndef
头文件必须包含c++检查
在c++检查之外包含外部头文件
首先用STL C文件包含外部头文件,然后是应用程序自定义文件
头文件必须包含其他所有头文件,以便正确编译,但不能包含更多头文件(如果需要,.c应该包含其余的头文件)
头文件必须只公开模块公共变量/类型/函数
在头文件中使用extern作为全局模块变量,稍后在源文件中定义它们
/*file.h...*/
#ifndef...
externint32_tmy_variable;/*Thisisglobalvariabledeclarationinheader*/
#endif
/*file.c...*/
int32_tmy_variable;/*Actuallydefinedinsource*/
不要把.c文件包含在另一个.c文件中
.c文件应该首先包含相应的.h文件,然后是其他文件,除非另有明确的必要
在头文件中不包含模块私有声明
头文件示例(示例中没有license)
/*Licensecomeshere*/
#ifndefTEMPLATE_HDR_H
#defineTEMPLATE_HDR_H
/*Includeheaders*/
#ifdef__cplusplus
extern"C"{
#endif/*__cplusplus*/
/*Filecontenthere*/
#ifdef__cplusplus
}
#endif/*__cplusplus*/
#endif/*TEMPLATE_HDR_H*/
本文来源网络,免费传达知识,版权归原作者所有。如涉及作品版权问题,请联系我进行删除。
在公众号聊天界面回复1024,可获取嵌入式资源
新闻来源:嵌入式大杂烩,文中所述为作者独立观点,不代表icspec立场。更多精彩资讯请下载icspec App。如对本稿件有异议,请联系微信客服specltkj。
