C/C++代码规范
零、前言
笔者最近在看开源代码,看到代码格式各自参差不齐,感觉像是各家各有所长。因此打算写一篇关于C/C++代码规范文章,请各位参考,并践踏批评。
一、文件排版
1. 包含头文件
• 先系统头文件,后用户头文件。
• 系统头文件,稳定的目录结构,应采用包含子路径方式。
• 自定义头文件,不稳定目录结构,应在dsp中指定包含路径。
• 系统头文件应用:#include <xxx.h>
• 自定义同文件应用:#include "xxx.h"
• 只引用需要的头文件。
2. h和cpp文件
• 头文件命名为.h,内联文件命名为.inl;C++文件命名为*.cpp
• 文件名用大小写混合,或者小写混合。例如DiyMainview.cpp
,infoview.cpp
。不要用无意义的名称:例如XImage.cpp
;SView.cpp
;xlog.cpp
;
• 头文件除了特殊情况,应使用#ifdef
控制块。
• 头文件#endif
应采用行尾注释。
• 头文件,首先是包含代码块,其次是宏定义代码块,然后是全局变量,全局常量,类型定义,类定义,内联部分。
• CPP文件,包含指令,宏定义,全局变量,函数定义。
3. 文件结构
• 文件应包含文件头注释和内容。
• 函数体类体之间原则上用2个空行,特殊情况下可用一个或者不需要空行。
4. 空行
• 文件头、控制块,#include
部分、宏定义部分、class
部分、全局常量部分、全局变量部分、函数和函数之间,用两个空行。
二、注释
1. 文件头注释
• 作者,文件名称,文件说明,生成日期(可选)
2. 函数注释
• 关键函数必须写上注释,说明函数的用途。
• 特别函数参数,需要说明参数的目的,由谁负责释放等等。
• 除了特别情况,注释写在代码之前,不要放到代码行之后。
• 对每个#else
或#endif
给出行末注释。
• 关键代码注释,包括但不限于:赋值,函数调用,表达式,分支等等。
• 善未实现完整的代码,或者需要进一步优化的代码,应加上 // TODO …
• 调试的代码,加上注释 // only for DEBUG
• 需要引起关注的代码,加上注释 // NOTE …
• 对于较大的代码块结尾,如for,while,do
等,可加上 // end for|while|do
三、命名
1. 原则
• 同一性:在编写一个子模块或派生类的时候,要遵循其基类或整体模块的命名风格,保持命名风格在整个模块中的同一性。
• 标识符组成:标识符采用英文单词或其组合,应当直观且可以拼读,可望文知意,用词应当准确,避免用拼音命名。
• 最小化长度 && 最大化信息量原则:在保持一个标识符意思明确的同时,应当尽量缩短其长度。
• 避免过于相似:不要出现仅靠大小写区分的相似的标识符,例如"i"与"I"
,"function"
与"Function"
等等。
• 避免在不同级别的作用域中重名:程序中不要出现名字完全相同的局部变量和全局变量,尽管两者的作用域不同而不会发生语法错误,但容易使人误解。
• 正确命名具有互斥意义的标识符:用正确的反义词组命名具有互斥意义的标识符,如:"nMinValue"
和"nMaxValue"
,"GetName()"
和"SetName()"
….
• 避免名字中出现数字编号:尽量避免名字中出现数字编号,如Value1,Value2等,除非逻辑上的确需要编号。这是为了防止程序员偷懒,不肯为命名动脑筋而导致产生无意义的名字(因为用数字编号最省事)。
2. T,C,M,R类
• T类表示简单数据类型,不对资源拥有控制权,在析构过程中没有释放资源动作。
• C表示从CBase继承的类。该类不能从栈上定义变量,只能从堆上创建。
• M表示接口类。
• R是资源类,通常是系统固有类型。除了特殊情况,不应在开发代码中出现R类型。
3. 函数名
• M类的函数名称应采用HandleXXX
命名,例如:HandleTimerEvent;
不推荐采用java风格,例如handleTimerEvent;
除了标准c风格代码,不推荐用下划线,例如,handle_event
。
• Leave函数,用后缀L。
• Leave函数,且进清除栈,用后缀LC。
• Leave函数,且删除对象,用后缀LD。
4. 函数参数
• 函数参数用a作为前缀。
• 避免出现和匈牙利混合的命名规则如apBuffer
名称。用aBuffer
即可。
• 函数参数比较多时,应考虑用结构代替。
• 如果不能避免函数参数比较多,应在排版上可考虑每个参数占用一行,参数名竖向对齐。
5. 成员变量
• 成员变量用m最为前缀。
• 避免出现和匈牙利混合的命名规则如mpBuffer名称。用mBuffer即可。
6. 局部变量
• 循环变量和简单变量采用简单小写字符串即可。例如,int i;
• 指针变量用p
打头,例如void* pBuffer;
7. 全局变量
• 全局变量用g_
最为前缀。
8. 类名
• 类和对象名应是名词。
• 实现行为的类成员函数名应是动词。
• 类的存取和查询成员函数名应是名词或形容词。
9. 风格兼容性
• 对于移植的或者开源的代码,可以沿用原有风格,不用C++的命名规范。
四、代码风格
1. Tab和空格
• 每一行开始处的缩进只能用Tab,建议tab用四个空格代替,感觉tab8个空格略长不美观。不能用空格,输入内容之后统一用空格。除了最开始的缩进控制用Tab,其他部分为了对齐,需要使用空格进行缩进。这样可以避免在不同的编辑器下显示不对齐的情况。
• 在代码行的结尾部分不能出现多余的空格。
• 不要在"::","->","."
前后加空格。
• 不要在",",";"
之前加空格。
2. 类型定义和{
• 类,结构,枚举,联合:大括号另起一行
3. 函数
• 函数体的{需要新起一行,在{之前不能有缩进。
• 除了特别情况,函数体内不能出现两个空行。
• 除了特别情况,函数体内不能宏定义指令。
• 在一个函数体内,逻揖上密切相关的语句之间不加空行,其它地方应加空行分隔。
• 在头文件定义的inline
函数,函数之间可以不用空行,推荐用一个空行。
4. 代码块
• "if"、"for"、"while"、"do"、"try"、"catch"
等语句自占一行,执行语句不得紧跟其后。不论执行语句有多少都要加 “{ }” 。这样可以防止书写和修改代码时出现失误。
• "if"、"for"、"while"、"do"、"try"、"catch"
的括号和表达式,括号可紧挨关键字,这样强调的是表达式。
5. else
• if语句如果有else语句,用 } else { 编写为一行,不推荐用 3 行代码的方式。
6. 代码行
• 一行代码只做一件事情,如只定义一个变量,或只写一条语句。这样的代码容易阅读,并且方便于写注释。
• 多行变量定义,为了追求代码排版美观,可将变量竖向对齐。
• 代码行最大长度宜控制在一定个字符以内,能在当前屏幕内全部可见为宜。
7. switch语句
• case关键字应和switch对齐。
• case子语句如果有变量,应用{}包含起来。
• 如果有并列的类似的简单case语句,可考虑将case代码块写为一行代码。
• 简单的case之间可不用空行,复杂的case之间应考虑用空行分割开。
• case字语句的大括号另起一行,不要和case写到一行。
• 为所有switch语句提供default分支。
• 若某个case不需要break一定要加注释声明。
8. 循环
• 空循环可用 for( ;; )
或者 while( 1 )
或者 while( true )
9. 类
• 类继承应采用每个基类占据一行的方式。
• 单继承可将基类放在类定义的同一行。如果用多行,则应用Tab缩进。
• 多继承在基类比较多的情况下,应将基类分行,并采用Tab缩进对齐。
• 重载基类虚函数,应在该组虚函数前写注释 // implement XXX
• 友元声明放到类的末尾。
10. 宏
• 不要用分号结束宏定义。
• 函数宏的每个参数都要括起来。
• 不带参数的宏函数也要定义成函数形式。
11. goto
• 尽量不要用goto
。
五、类型
• 定义指针和引用时*和&紧跟类型。
• 尽量避免使用浮点数,除非必须。
• 用typedef
简化程序中的复杂语法。
• 避免定义无名称的类型。例如:typedef enum { EIdle, EActive } TState;
• 少用union,如果一定要用,则采用简单数据类型成员。
• 用enum
取代(一组相关的)常量。
• 不要使用魔鬼数字。
• 尽量用引用取代指针。
• 定义变量完成后立即初始化,勿等到使用时才进行。
• 如果有更优雅的解决方案,不要使用强制类型转换。
六、表达式
• 避免在表达式中用赋值语句。
• 避免对浮点类型做等于或不等于判断。
• 不能将枚举类型进行运算后再赋给枚举变量。
• 在循环过程中不要修改循环计数器。
七、函数
1. 引用
• 引用类型作为返回值:函数必须返回一个存在的对象。
• 引用类型作为参数:调用者必须传递一个存在的对象。
2. 常量成员函数
• 表示该函数只读取对象的内容,不会对对象进行修改。
3. 返回值
• 除开void
函数,构造函数,析构函数,其它函数必须要有返回值。
• 当函数返回引用或指针时,用文字描述其有效期。
4. 内联函数
• 内联函数应将函数体放到类体外。
• 只有简单的函数才有必要设计为内联函数,复杂业务逻辑的函数不要这么做。
• 虚函数不要设计为内联函数。
5. 函数参数
• 只读取该参数的内容,不对其内容做修改,用常量引用。
• 修改参数内容,或需要通过参数返回,用非常量应用。
• 简单数据类型用传值方式。
• 复杂数据类型用引用或指针方式。
八、类
1. 构造函数
• 构造函数的初始化列表,应和类的顺序一致。
• 初始化列表中的每个项,应独占一行。
• 避免出现用一个成员初始化另一个成员。
• 构造函数应初始化所有成员,尤其是指针。
• 不要在构造函数和析构函数中抛出异常。
2. 纯虚函数
• M类的虚函数应设计为纯虚函数。
3. 构造和析构函数
• 如果类可以继承,则应将类析构函数设计为虚函数。
• 如果类不允许继承,则应将类析构函数设计为非虚函数。
• 如果类不能被复制,则应将拷贝构造函数和赋值运算符设计为私有的。
• 如果为类设计了构造函数,则应有析构函数。
4. 成员变量
• 尽量避免使用mutable
和Volatile
。
• 尽量避免使用公有成员变量。
5. 成员函数
• 努力使类的接口少而完备。
• 尽量使用常成员函数代替非常成员函数,const
函数
• 除非特别理由,绝不要重新定义(继承来的)非虚函数。(这样是覆盖,基类的某些属性无初始化)
6. 继承
• 继承必须满足IS-A的关系,HAS-A应采用包含。
• 虚函数不要采用默认参数。
• 除非特别需要,应避免设计大而全的虚函数,虚函数功能要单一。
• 除非特别需要,避免将基类强制转换成派生类。
7. 友元
• 尽量避免使用友元函数和友元类。
九、错误处理
• 申请内存用new操作符。
• 释放内存用delete操作符。
• new
和delete
,new[]
和delete[]
成对使用。
• 申请内存完成之后,要检测指针是否申请成功,处理申请失败的情况。
• 谁申请谁释放。优先级:函数层面,类层面,模块层面。
• 释放内存完成后将指针赋空,避免出现野指针。
• 使用指针前进行判断合法性,应考虑到为空的情况的处理。
• 使用数组时,应先判断索引的有效性,处理无效的索引的情况。
• 代码不能出现编译警告。
• 使用错误传递的错误处理思想。
• 卫句风格:先处理所有可能发生错误的情况,再处理正常情况。
• 嵌套do-while(0)
宏:目的是将一组语句变成一个语句,避免被其他if等中断。
C/C++代码规范的更多相关文章
- iOS代码规范(OC和Swift)
下面说下iOS的代码规范问题,如果大家觉得还不错,可以直接用到项目中,有不同意见 可以在下面讨论下. 相信很多人工作中最烦的就是代码不规范,命名不规范,曾经见过一个VC里有3个按钮被命名为button ...
- 谈谈PHP代码规范
[转] http://www.syyong.com/php/Talk-about-PHP-code-specification.html 我向往这样一个php世界,里面没有代码规范之争.你我都一样,都 ...
- 2016 正确 sublime安装PHPcs PHPcodesniffer代码规范提示插件,修正网上部分不详细描述
对你有助请点赞,请顶,不好请踩------送人玫瑰,手留余香!-------------------14:37 2016/3/212016 正确 sublime安装PHPcs PHPcodesniff ...
- C#与Java对比学习:类型判断、类与接口继承、代码规范与编码习惯、常量定义
类型判断符号: C#:object a; if(a is int) { } 用 is 符号判断 Java:object a; if(a instanceof Integer) { } 用 inst ...
- 作业三: 代码规范、代码复审、PSP
分) 对于是否需要有代码规范,请考虑下列论点并反驳/支持: 这些规范都是官僚制度下产生的浪费大家的编程时间.影响人们开发效率, 浪费时间的东西. 我是个艺术家,手艺人,我有自己的规范和原则. 规范不能 ...
- 转!!Java代码规范、格式化和checkstyle检查配置文档
为便于规范各位开发人员代码.提高代码质量,研发中心需要启动代码评审机制.为了加快代码评审的速度,减少不必要的时间,可以加入一些代码评审的静态检查工具,另外需要为研发中心配置统一的编码模板和代码格式化模 ...
- C#代码规范
C#代码规范 一.文件命名 1 文件名 文件名统一使用帕斯卡命名法,以C#类名命名,拓展名小写. 示例: GameManager.cs 2 文件注释 每个文件头须包含注释说明,文件头位置指的是文件最 ...
- 【转】Java代码规范
[转]Java代码规范 http://blog.csdn.net/huaishu/article/details/26725539
- 作业三:代码规范、代码复审、PSP
一.代码规范 我认为我们编写的代码都需要进行规范的操作,因为如果为了图省事情或者为了减少时间去完成这个编程.在最后检验的时候就会出现一些警告,导致你这次编程的代码出现问题,当出现问题的时候你在回头去检 ...
- 关于"是否需要有代码规范"的个人看法
这些规范都是官僚制度下产生的浪费大家的编程时间.影响人们开发效率, 浪费时间的东西. 我是个艺术家,手艺人,我有自己的规范和原则. 规范不能强求一律,应该允许很多例外. 我擅长制定编码规范,你们听我的 ...
随机推荐
- web框架学习路线
0.配置 1.路由 2.view 3.model 4.序列化与反序列化. 5.auth&permission 6.header处理 7.http client
- ubuntu16.04 下通过rc.d(rc.local)实现开机启动(未登录)anydesk
先编辑anydesk-X.X.X/init/anydesk文件,将"DAEMON=//usr/bin$NAME"改成"DAEMON=/XXX/anydesk-5.1.1/ ...
- tomcat-APR配置及三种工作模式简介
安装软件包,之前可以用rpm -q 命令查看一下是否存在,如果有这两个软件包先卸载再重新安装yum -y install apr apr-devel 拷贝Tomcat安装目录下的bin目录下的tomc ...
- libvirt2.0安装
目录 1.libvirt介绍 2.卸载系统自带的libvirt 2.1.查看当前安装的libvirt相关包 2.2.全部卸载掉 3.使用tar包编译安装 3.1.解压缩 3.2.生成Makefile文 ...
- KVM虚拟化介绍(1)
一.虚拟化分类 1.虚拟化,是指通过虚拟化技术将一台计算机虚拟为多台逻辑计算机.在一台计算机上同时运行多个逻辑计算机,每个逻辑计算机可运行不同的操作系统,并且应用程序都可以在相互独 立的空间内运 ...
- 产品之我见(1)-女性APP
我曾下载过几款女性APP,下载的初衷是想要记录.同时预估下一次生理周期开始的时间. 在查找网上测评推荐及个人下载试用了四五款后,我当时留下美柚.大姨吗.Clue这三款. 美柚 ...
- Linux下配置APUE的编译 报错之后如何处理
APUE即Unix环境高级编程,本书中几乎所有的程序都包含一个apue.h的头文件,那如何配置这个apue.h呢? 官方地址:http://www.apuebook.com/apue3e.html 1 ...
- 使用JQuery获取被选中的checkbox的value值
上网查了一下,感觉一些人回答得真的是不知所云,要么代码不够简便.或者是有些想装逼成分等. 以下为使用JQuery获取input checkbox被选中的值代码: <html> & ...
- Linux (x86) Exploit 开发系列教程之四(使用return-to-libc绕过NX bit)
(1)原理: “NX Bit”的漏洞缓解:使某些内存区域不可执行,并使可执行区域不可写.示例:使数据,堆栈和堆段不可执行,而代码段不可写. 在NX bit打开的情况下,基于堆栈的缓冲区溢出的经典方法将 ...
- (转)查找算法:二叉排序树(BSTree)
二叉排序树(Binary Sort Tree),又称为二叉查找树(Binary Search Tree) ,即BSTree. 构造一棵二叉排序树的目的,其实并不是为了排序,而是为了提高查找和插入删除的 ...