0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
会员中心
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

嵌入式C编码需要遵循的规范有哪些?

电子森林 来源:TsinghuaJoking 作者:TsinghuaJoking 2021-06-21 15:07 次阅读

1最重要的规则

编写代码时最重要的一条规则是:检查周围的代码并尝试模仿它。

作为维护人员,如果收到的补丁明显与周围代码的编码风格不同,这是令人沮丧的。这是不尊重人的,就像某人穿着泥泞的鞋子走进一间一尘不染的房子。

因此,无论本文推荐的是什么,如果已经编写了代码并且您正在对其进行修补,请保持其当前的样式一致,即使它不是您最喜欢的样式。

2一般性的规则

这里列出了最明显和最重要的一般规则。在你继续阅读其他章节之前,请仔细检查它们。

使用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*/ voidmy_func(void){ staticint32_t*ptr;/*OK*/ staticcharabc=0;/*Wrong*/ }

在同一行中声明所有相同类型的局部变量

voidmy_func(void){ chara;/*OK*/ charb;/*Wrong,variablewithchartypealreadyexists*/ chara,b;/*OK*/ }

按顺序声明局部变量

i. 自定义结构和枚举

ii. 整数类型,更宽的无符号类型优先

iii. 单/双浮点

intmy_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, if you need counter variable later */ size_t i; for (i = 0; i < 10; ++i) {     if (...) {         break;     } } if (i * 10) { } /* Wrong */ size_t i; for (i = 0; i < 10; ++i) ...

避免在声明中使用函数调用来赋值变量,除了单个变量

voida(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 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*/ voidsend_data(constvoid*data,size_tlen){/*OK*/ /*Donotcast`void*`or`constvoid*`*/ constuint8_t*d=data;/*Functionhandlespropertypeforinternalusage*/ } voidsend_data(constvoid*data,intlen){/*Wrong,notnotuseint*/ }

总是使用括号和sizeof操作符

不要使用变长数组。使用动态内存分配代替标准Cmalloc和自由函数,或者如果库/项目提供了自定义内存分配,使用它的实现看看LwMEM,一个自定义内存管理库。

/*OK*/ #include 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

始终尊重项目或库中已经使用的代码风格

3注释相关的规则

不允许以//开头的注释。总是使用② comment */,即使是单行注释

对于多行注释,每行使用空格+星号

/* *Thisismulti-linecomments, *writtenin2lines(ok) */ /** *Wrong,usedouble-asteriskonlyfordoxygendocumentation */ /* *Singlelinecommentwithoutspacebeforeasterisk(wrong) */ /* *Singlelinecommentinmulti-lineconfiguration(wrong) */ /*Singlelinecomment(ok)*/

注释时使用12个缩进(12 * 4个空格)偏移量。如果语句大于12个缩进,将注释4-空格对齐(下面的例子)到下一个可用缩进

voidmy_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*/ }

04函数定义的规则

每个可以从模块外部访问的函数都必须包含函数原型(或声明)

函数名必须小写,可以用下划线_分隔。(这个原则好像因人而异)

/*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! "; } /*Wrong*/ int32_tfoo(void){ return0; }

5变量相关的规则

使变量名全部小写,下划线_字符可选

/*OK*/ int32_ta; int32_tmy_var; int32_tmyvar; /*Wrong*/ int32_tA; int32_tmyVar; int32_tMYVar;

按类型将局部变量分组在一起

voidfoo(void){ int32_ta,b;/*OK*/ chara; charb;/*Wrong,chartypealreadyexists*/ }

不要在第一个可执行语句之后声明变量

voidfoo(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;

6结构、枚举类型定义

结构名或枚举名必须小写,单词之间有下划线_字符

结构或枚举可以包含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};

当为函数句柄引入newtypedef时,使用_fn后缀

/*Functionaccepts2parametersandreturnsuint8_t*/ /*Nameoftypedefhas`_fn`suffix*/ typedefuint8_t(*my_func_typedef_fn)(uint8_tp1,constchar*p2);

07复合语句规则

每个复合语句必须包括左花括号和右花括号,即使它只包含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, empty loop contains no spaces inside curly brackets */ while (*addr & (1 << 13)) { }       /* Wrong */ while (*addr & (1 << 13)) {         /* Wrong */ } while (*addr & (1 << 13));          /* Wrong, curly brackets are missing. Can lead to compiler warnings or unintentional bugs */

尽量避免在循环块内递增变量,参见示例

/*Notrecommended*/ int32_ta=0; while(a< 10) {     .     ..     ...     ++a; } /* Better */ for (size_t a = 0; a < 10; ++a) { } /* Better, if inc may not happen in every cycle */ for (size_t a = 0; a < 10; ) {     if (...) {         ++a;     } }

8分支语句规则

为每个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; }

9 宏和预处理指令

总是使用宏而不是文字常量,特别是对于数字

所有的宏必须是全大写的,并带有下划线_字符(可选),除非它们被明确标记为function,将来可能会被常规函数语法替换

/*OK*/ #defineMY_MACRO(x)((x)*(x)) /*Wrong*/ #definesquare(x)((x)*(x))

总是用圆括号保护输入参数

/*OK*/ #defineMIN(x,y)((x)< (y) ? (x) : (y)) /* Wrong */ #define MIN(x, y)           x < y ? x : y

总是用括号保护最终的宏计算

/*Wrong*/ #defineMIN(x,y)(x)< (y) ? (x) : (y) #define SUM(x, y)           (x) + (y) /* Imagine result of this equation using wrong SUM implementation */ int32_t x = 5 * SUM(3, 4);  /* Expected result is 5 * 7 = 35 */ int32_t x = 5 * (3) + (4);  /* It is evaluated to this, final result = 19 which is not what we expect */ /* Correct implementation */ #define MIN(x, y)           ((x) < (y) ? (x) : (y)) #define SUM(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个制表符)作为文本行开始的偏移量

/** *riefHoldspointertofirstentryinlinkedlist *Beginningofthistextis5tabs(20spaces)frombeginningofline */ static type_t*list;

每个结构/枚举成员都必须包含文档

注释的开头使用12x4空格偏移量

/** *riefThisispointstruct * oteThisstructureisusedtocalculateallpoint *relatedstuff */ typedefstruct{ int32_tx;/*!< Point X coordinate */     int32_t y;                                  /*!< Point Y coordinate */     int32_t size;                               /*!< Point size.                                                     Since comment is very big,                                                     you may go to next line */ } point_t; /**  * rief           Point color enumeration  */ typedef enum {     COLOR_RED,                                  /*!< Red color. This comment has 12x4                                                     spaces offset from beginning of line */     COLOR_GREEN,                                /*!< Green color */     COLOR_BLUE,                                 /*!< Blue color */ } point_color_t;

函数的文档必须在函数实现中编写(通常是源文件)

函数必须包括简要和所有参数文档

如果每个参数分别为in或out输入和输出,则必须注意

如果函数返回某个值,则必须包含返回形参。这不适用于void函数

函数可以包含其他doxygen关键字,如note或warning

在参数名和描述之间使用冒号:

/** *riefSum`2`numbers *param[in]a:Firstnumber *param[in]b:Secondnumber *returnSumofinputvalues */ int32_t sum(int32_ta,int32_tb){ returna+b; } /** *riefSum`2`numbersandwriteittopointer * oteThisfunctiondoesnotreturnvalue,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关键字指定哪个成员

/** *riefMyenumeration */ typedefenum{ MY_ERR,/*!< Error value */     MY_OK                                       /*!< OK value */ } my_enum_t; /**  * rief           Check some value  * return           ef MY_OK on success, member of  ef my_enum_t otherwise  */ my_enum_t check_value(void) {     return MY_OK; }

对常量或数字使用符号(' NULL ' => NULL)

/** *riefGetdatafrominputarray *param[in]in:Inputdata *returnPointertooutputdataonsuccess,`NULL`otherwise */ constvoid* get_data(constvoid*in){ returnin; }

宏的文档必须包括hideinitializer doxygen命令

/** *riefGetminimalvaluebetween`x`and`y` *param[in]x:Firstvalue *param[in]y:Secondvalue *returnMinimalvaluebetween`x`and`y` *hideinitializer */ #defineMIN(x,y)((x)< (y) ? (x) : (y))

10头/源文件

在文件末尾留下一个空行

每个文件都必须包括文件的doxygen注释和后跟空行的简要描述(使用doxygen时)

/** *filetemplate.h *riefTemplateincludefile */ /*Hereisemptyline*/

每个文件(头文件或源文件)必须包含许可证(开始注释包括单个星号,因为doxygen必须忽略这个)

使用与项目/库已经使用的相同的许可证

/** *filetemplate.h *riefTemplateincludefile */ /* *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 */@example.com>

头文件必须包含保护符#ifndef

头文件必须包含c++检查

在c++检查之外包含外部头文件

首先用STLC文件包含外部头文件,然后是应用程序自定义文件

头文件必须包含其他所有头文件,以便正确编译,但不能包含更多头文件(如果需要,.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*/

责任编辑:lq6

声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • 嵌入式
    +关注

    关注

    5057

    文章

    18964

    浏览量

    301816
  • 函数
    +关注

    关注

    3

    文章

    4276

    浏览量

    62314
  • 代码
    +关注

    关注

    30

    文章

    4719

    浏览量

    68210

原文标题:嵌入式C编码规范

文章出处:【微信号:xiaojiaoyafpga,微信公众号:电子森林】欢迎添加关注!文章转载请注明出处。

收藏 人收藏

    评论

    相关推荐

    嵌入式学习建议

    原理的嵌入式操作系统进行学习。不要一开始就学习几种操作系统,理解了基本原理,实践中确有实际需要再学习也不迟。人总是要不断学习的。 ⑨关于汇编语言与C语言的取舍。随着:MCU对C编译的
    发表于 10-22 11:41

    嵌入式主板是什么意思?嵌入式主板全面解析

    嵌入式主板,通常被称为嵌入式系统的核心组件,是一种用于控制和数据处理的计算机硬件,其设计旨在嵌入特定设备中执行专门任务。嵌入式主板如同是设备的“大脑”,主要功能是根据
    的头像 发表于 09-30 10:05 308次阅读

    嵌入式常用总线哪些

    嵌入式系统中常用的总线种类繁多,它们各自具有不同的特点和应用场景。以下将详细介绍几种嵌入式开发中常用的总线,包括UART、I2C、SPI、RS-232、RS-485、CAN以及USB等,每种总线将从其定义、特点、工作原理、应用场
    的头像 发表于 09-10 11:34 430次阅读

    嵌入式linux开发的基本步骤哪些?

    之前,首先需要选择合适的硬件平台。硬件选择需要考虑以下几个方面: 1.1 处理器 嵌入式Linux开发需要一个处理器,常见的处理器ARM、
    的头像 发表于 09-02 09:11 336次阅读

    如何成为一名嵌入式C语言高手?

    如何成为一名嵌入式C语言高手? 嵌入式系统是当今科技领域的核心,而C语言则是嵌入式系统开发中最常用的编程语言之一。成为一名
    发表于 04-07 16:03

    如何成为一名嵌入式C语言高手?

    如何成为一名嵌入式C语言高手? 嵌入式系统是当今科技领域的核心,而C语言则是嵌入式系统开发中最常用的编程语言之一。成为一名
    发表于 03-25 14:12

    嵌入式工程师需要掌握哪些技术?

    嵌入式系统通常需要与其他设备或系统进行通信。了解常见的通信协议,如UART、SPI、I2C、CAN和Ethernet等,以及它们的工作原理和使用方法是必不可少的。此外,对于无线通信协议,如
    发表于 03-04 16:38

    定制嵌入式主板,需要考虑的功能有哪些?

    随着科技的不断发展和进步,嵌入式系统在各行各业中得到了广泛的应用。嵌入式主板作为嵌入式系统的核心组件,起着至关重要的作用。在定制嵌入式主板时,需要
    的头像 发表于 02-29 17:38 460次阅读
    定制<b class='flag-5'>嵌入式</b>主板,<b class='flag-5'>需要</b>考虑的功能有哪些?

    嵌入式人工智能的就业方向哪些?

    的发展方向很多,门槛高低不一样。下面给大家列举一些相应岗位所需具备的技能: 一:嵌入式Linux,C语言开发工程师,Linux软件开发工程师 LinuxC语言开发 LinuxC语言开发进阶 Linux
    发表于 02-26 10:17

    聊一聊嵌入式C语言

    作为一名嵌入式软件开发者,熟练掌握嵌入式C语言对我的日常工作至关重要。
    的头像 发表于 01-22 09:28 507次阅读

    C语言构建高效的嵌入式程序

    嵌入式工程师在编写C语言程序时,需要注重效率和清晰的思路。本文将通过解析经典问题“猴子选大王”来展示如何用C语言思维方式构建高效、清晰的程序。
    的头像 发表于 12-21 09:27 582次阅读

    嵌入式C编码文件头申明规范

    编码规范 2.1 文件头申明 ◎ 新增.c必须添加注释,标注公司名称、文件功能说明,创建日期、作者,后续修改说明 范例
    的头像 发表于 12-07 14:29 384次阅读

    嵌入式C语言的结构特点

    嵌入式开发中既有底层硬件的开发又涉及上层应用的开发,即涉及系统的硬件和软件,C语言既具有汇编语言操作底层的优势,又具有高级语言功能性强的特点,当之无愧地成为嵌入式开发的主流语言。在 STM32开发
    的头像 发表于 11-24 16:16 616次阅读
    <b class='flag-5'>嵌入式</b><b class='flag-5'>C</b>语言的结构特点

    嵌入式系统的C语言

    电子发烧友网站提供《嵌入式系统的C语言.doc》资料免费下载
    发表于 11-18 14:39 2次下载
    <b class='flag-5'>嵌入式</b>系统的<b class='flag-5'>C</b>语言

    c语言嵌入式开发

    电子发烧友网站提供《c语言嵌入式开发.zip》资料免费下载
    发表于 11-17 14:11 2次下载
    <b class='flag-5'>c</b>语言<b class='flag-5'>嵌入式</b>开发