4.DoSomething();
5....
6.}
1.//假设下面的函数调用不满足行宽要求,需要换行
2.ReturnTyperesult=FunctionName(paramName1,
3.paramName2,
4.paramName3);//保持与上方参数对齐
1.ReturnTyperesult=VeryVeryVeryLongFunctionName(//写入第1个参数后导致过长,直接换行
2.paramName1,paramName2,paramName3);//换行后,4空格缩进一层
1.//每行的参数代表一组相关性较强的数据结构,放在一行便于理解,此时可理解性优先于格式排版要求
2.intresult=DealWithStructLikeParams(left.x,left.y,//表示一组相关参数
3.right.x,right.y);//表示另外一组相关参数
∙声明定义函数时,函数的返回类型以及其他修饰符,与函数名同行
∙指针类型"*"应该靠右跟随变量或者函数名,比如:
1.int*p1;//Good:
右跟随变量,和左边的类型隔了1个空格
2.int*p2;//Bad:
左跟随类型
3.int*p3;//Bad:
两边都没空格
4.int*p4;//Bad:
两边都有空格
当"*"与变量或函数名之间有其他修饰符,无法跟随时,此时也不要跟随修饰符,比如:
1.char*constVERSION="V100";//Good:
当有const修饰符时,"*"两边都有空格
2.intFoo(constchar*restrictp);//Good:
当有restrict修饰符时,"*"两边都有空格
∙根据上下内容的相关程度,合理安排空行,但不要使用连续3个或更多空行
∙编译预处理的"#"统一放在行首,无需缩进。
嵌套编译预处理语句时,"#"可以进行缩进,比如:
1.#ifdefined(__x86_64__)&&defined(__GCC_HAVE_SYNC_COMPARE_AND_SWAP_16)//位于行首,不缩进
2.#defineATOMIC_X86_HAS_CMPXCHG16B1//缩进一层,区分层次,便于阅读
3.#else
4.#defineATOMIC_X86_HAS_CMPXCHG16B0
5.#endif
注释
∙注释的内容要清楚、明了,含义准确,防止注释二义性
∙在代码的功能、意图层次上进行注释,即注释解释代码难以直接表达的意图,而不是仅仅重复描述代码
∙函数声明处注释描述函数功能、性能及用法,包括输入和输出参数、函数返回值、可重入的要求等;定义处详细描述函数功能和实现要点,如实现的简要步骤、实现的理由、设计约束等
∙全局变量要有较详细的注释,包括对其功能、取值范围以及存取时注意事项等的说明
∙避免在注释中使用缩写,除非是业界通用或子系统内标准化的缩写
∙文件头部要进行注释,建议注释列出:
版权说明、版本号、生成日期、作者姓名、功能说明、与其它文件的关系、修改日志等
∙注释风格要统一,建议优先选择/**/的方式,注释符与注释内容之间要有1空格,单行、多行注释风格如下:
1./*单行注释*/
1./*
2.*多行注释
3.*第二行
4.*/
∙注释应放在其代码上方或右方
上方的注释,与代码行之间无空行,保持与代码一样的缩进。
右边的注释,与代码之间至少相隔1个空格。
如果有多条右置注释,上下对齐会更加美观,比如:
1.#defineA_CONST100//此处两行注释属于同类
2.#defineANOTHER_CONST200//可保持左侧对齐
宏
∙代码片段使用宏隔离时,统一通过#ifdef的方式,例如:
1.#ifdefLOSCFG_XXX
2....
3.#endif
∙定义宏时,要使用完备的括号,比如:
1.#defineSUM(a,b)a+b//不符合本条要求
2.#defineSUM(a,b)((a)+(b))//符合本条要求
但是也要避免滥用括号,比如单独的数字或标识符加括号毫无意义:
1.#defineSOME_CONST100//单独的数字无需括号
2.#defineANOTHER_CONST(-1)//负数需要使用括号
3.#defineTHE_CONSTSOME_CONST//单独的标识符无需括号
∙包含多条语句的函数式宏的实现语句必须放在do-while(0)中,例如:
1.#defineFOO(x)do{\
2.(void)printf("argis%d\n",(x));\
3.DoSomething((x));\
4.}while(0)
∙禁止宏调用参数中出现预编译指令
∙宏定义不以分号结尾
头文件
∙设计原则
▪头文件应当职责单一
▪一个模块通常包含多个.c文件,建议放在同一个目录下,目录名即为模块名;如果一个模块包含多个子模块,则建议每一个子模块提供一个对外的.h,文件名为子模块名
▪建议每一个.c文件应有一个同名.h文件,用于声明需要对外公开的接口
▪头文件中适合放置接口的声明,不适合放置实现
▪不要在头文件中定义变量
▪禁止头文件循环依赖,循环依赖指a.h包含b.h,b.h包含c.h,c.h包含a.h
▪头文件应当自包含,即任意一个头文件均可独立编译,但同时也要避免包含用不到的头文件
▪头文件必须用#define保护,防止重复包含,比如内核中统一使用以下宏定义保护:
▪禁止通过声明的方式引用外部函数接口、变量,只能通过包含头文件的方式使用其他模块或文件提供的接口
▪禁止在extern"C"中包含头文件
▪按照合理的顺序包含头文件:
o源文件对应的头文件
oC标准库
o需要包含的OS其他头文件
∙版权声明
▪头文件版权声明一致,放在头文件置顶位置
▪如果提交的代码是在开源软件基础上修改所编写或衍生的代码,请遵循开源许可协议要求,并且已履行被修改软件的许可证义务
数据类型
∙基础类型定义统一使用los_typedef.h中定义的类型,比如定义无符号32位整型变量使用UINT32
变量
∙一个变量只有一个功能,不要把一个变量用作多种用途
∙防止局部变量与全局变量同名
∙不用或者少用全局变量
∙定义函数的局部变量时,控制变量的占用空间,避免因占用过多栈空间导致程序运行失败。
比如需要一个大数组,可以通过动态分配内存的方式来避免栈空间占用过大
∙在首次使用前初始化变量
∙指向资源句柄或描述符的变量,在资源释放后立即赋予新值,包括指针、socket描述符、文件描述符以及其它指向资源的变量
∙禁止将局部变量的地址返回到其作用域以外,下面是一个错误示例:
1.int*Func(void)
2.{
3.intlocalVar=0;
4....
5.return&localVar;//错误
6.}
7.
8.voidCaller(void)
9.{
10.int*p=Func();
11....
12.intx=*p;//程序产生未定义行为
13.}
正确代码示例:
1.intFunc(void)
2.{
3.intlocalVar=0;
4....
5.returnlocalVar;
6.}
7.
8.voidCaller(void)
9.{
10.intx=Func();
11....
12.}
∙如果要使用其他模块的变量,应尽量避免直接对变量进行访问,而是通过统一的函数封装或者宏封装的方式,比如mutex模块中:
1.//私有头文件中引入全局变量,但要避免直接使用
2.externLosMuxCB*g_allMux;
3.//通过GET_MUX的方式对g_allMux进行访问
4.#defineGET_MUX(muxID)(((LosMuxCB*)g_allMux)+GET_MUX_INDEX(muxID))
函数
∙重复代码应该尽可能提炼成函数
∙避免函数过长,新增函数不超过40-50行
∙内联函数要尽可能短,避免超过10行(非空非注释)
∙避免函数的代码块嵌套过深
∙函数应避免使用全局变量、静态局部变量和I/O操作,不可避免的地方应集中使用
可移植性
不使用与硬件或操作系统关系很大的语句,而使用建议的标准语句,以提高软件的可移植性和可重用性。
业界编程规范
C语言编程规范参考资料较多,大家可以自行了解,本文不再过多赘述。