c++编程规范

本文详细阐述了C++编程中的命名规范(包括文件、函数、命名空间、变量等)、排版规范(如缩进、空行等)、注释规范(文件、源文件、结构体/类等)以及设计规范(头文件结构、定义位置、单例类等)。这些规则有助于提高代码可读性和一致性。
摘要由CSDN通过智能技术生成

一、命名规范

1、目录/文件

规范:使用小写字母、数字、下划线,多个单词间用下划线分隔。
原因:Windows对目录和文件是大小写不区分的,而Linux是大小写区分的。为了达到平台统一,这里规定都使用小写字母。
示例:

目录:app_cxx/proc_ui/src/firewall
文件:firewall_mgr.h、main.cpp、nfsv2.cpp

2、函数/接口

规范:使用小驼峰命名法。
原因:大部分著名的开源项目以及大厂对外提供的API都是这样的命名规范。
示例:


int test()
{
    return 0;
}

int getLocalPort()
{
    return 4335;
}

3、命名空间

规范:使用小写字母、数字、下划线,多个单词间用下划线分隔 (尽量只使用一个单词),
示例:

namespace logger
{
}

4、结构体/类

规范:使用大驼峰命名法,不包含下划线
示例:

struct SendData
{
};

class LoggerManager
{
};

5、变量

规范:使用小驼峰命名法。

(1)局部变量

示例:

void test()
{
    int reqNum = 0;
}
(2)全局变量

补充:需要加前缀g_
示例:

int g_reqNum= 0;
(3)静态变量

补充:需要加前缀s_
示例:

void test()
{
    static int s_reqNum = 0;
}

补充:当它同时也是全变量时使用全局变量的命名方式
示例:

int g_reqNum = 0;
(4)类成员变量

补充:需要加前缀m_
示例:

class ServerInfo
{
private:
    int m_reqNum
}
(5)类静态变量

补充:需要加前缀s_
示例:

class ServerInfo
{
private:
    static int s_reqNum;
}
(6)常量

补充:需要大写字母
示例:

const int MAX_NUM = 1024;

5、宏定义

规范:需要大写字母
示例:

#define CACHE_PATH "/data/cache"

6、枚举

规范:枚举名使用大驼峰命名法,枚举名建议带上class类型,枚举值需要小写字母
原因:避免和宏定义冲突
示例:

enum class ResultType
{
    ok,
    open_fail,
    unknown
};

二、排版规范

1、缩进

程序块要采用缩进风格编写,缩进的空格数为 4 个

2、 独立说明加空行

相对独立的程序块之间、变量说明之后必须加空行

示例:

if (!valid_ni(ni))  
{  
... // program code  
}  

repssn_ind = ssn_data[index].repssn_index;  
repssn_ni = ssn_data[index].ni; 

3、 字符 80+ 多行书写

较长语句(>80字符)分多行书写,长表达式要在低优先级操作符处划分新行,操作符放在新行之首,划分出的新行要适当缩进

perm_count_msg.head.len = NO7_TO_STAT_PERM_COUNT_LEN 
                    + STAT_SIZE_PER_FRAM * sizeof( _UL ); 

act_task_table[frame_id * STAT_TASK_CHECK_NUMBER + index].occupied 
            = stat_poi[index].occupied;

report_or_not_flag = ((taskno < MAX_ACT_TASK_NUMBER)
               && (n7stat_stat_item_valid (stat_item)) 
               && (act_task_table[taskno].result_data != 0));

4、 较长语句进行划分

循环、判断等语句中若有较长的表达式或语句,要进行适应划分,长表达式要在低优先级操作符处划分新行,操作符放在新行之首

示例:

if ((taskno < max_act_task_number) 
   && (n7stat_stat_item_valid (stat_item))) 
{ 
   ... // program code 
} 
for (i = 0, j = 0; (i < BufferKeyword[word_index].word_length) 
               && (j < NewKeyword.word_length); i++, j++) 
{ 
   ... // program code 
} 

for (i = 0, j = 0; 
   (i < first_word_length) && (j < second_word_length); 
   i++, j++) 
{ 
   ... // program code 
}

5、 内嵌语句独占且加括号

if、for、do、while、case、switch、default 等语句自占一行,且 if、for、do、while 等的执行语句部分要加括号{ }

if (pUserCR == NULL) 
{ 
return; 
}

6、 空格对齐

对齐只使用空格键,不使用TAB键。

// 说明:以免用不同的编辑器阅读程序时,因 TAB 键所设置的空格数目不同而造成程序布局
// 不整齐,不要使用 BC 作为编辑器合版本,因为 BC 会自动将 8 个空格变为一个 TAB 键,
// 因此使用 BC 合入的版本大多会将缩进变乱。

7、 操作符与空格

在两个以上关键字、变量、常量对等操作时,之间的操作符之前、之后或前后加空格;非对等操作时,关系密切的立即操作符(如->)后不加空格

(1)“!”、“~”、“++”、“–”、“&”(地址运算符)等单目操作符前后不加空格。

*p = 'a'; // 内容操作"*"与内容之间
flag = !isEmpty; // 非操作"!"与内容之间
p = &mem; // 地址操作"&" 与内容之间
i++; // "++","--"与内容之间

(2)“->”、"."前后不加空格。

p->id = pid; // "->"指针前后不加空格

(3) if、for、while、switch 等与后面的括号间应加空格,使 if 等关键字更为突出、明显。

if (a >= b && c > d)

三、注释规范

规范:尽量用/* */进行注释,避免使用//。
原因:使用//时,当不小心把其下面的一行代码回退到//所在行时,如果没注意的话容易造成逻辑出错。

1 、说明文件

说明性文件(.h文件、.inc文件、.def文件、编译说明文件.cfg等)头部应注释,必须列出:版权说明、版本号、生成日期、作者、内容、功能、与其它文件的关系、修改日志等,还应有函数功能简要说明。

/*************************************************** 
 Copyright (C), Your Company 
 File name: // 文件名
 Author: Version: Date: // 作者、版本及完成日期
 Description: // 用于详细说明此程序文件完成的主要功能,与其他模块
              // 或函数的接口,输出值、取值范围、含义及参数间的控
              // 制、顺序、独立或依赖等关系
 Others: // 其它内容的说明
 Function List: // 主要函数列表,每条记录应包括函数名及功能简要说明
   1. .... 
 History: // 修改历史记录列表,每条修改记录应包括修改日期、修改
          // 者及修改内容简述 
   1. Date: 
      Author: 
      Modification: 
   2. ... 
***************************************************/

2、 源文件

源文件头部应注释,列出:版权说明、版本号、生成日期、作者、模块目的/功能、主要函数及其功能、修改日志等。

/************************************************************ 
 Copyright (C), 1988-1999, Huawei Tech. Co., Ltd. 
 FileName: test.cpp 
 Author: Version : Date: 
 Description: // 模块描述 
 Version: // 版本信息
 Function List: // 主要函数及其功能
   1. ------- 
 History: // 历史修改记录
     <author> <time> <version > <desc> 
     David 96/10/12 1.0 build this moudle 
***********************************************************/ 
说明:Description 一项描述本文件的内容、功能、内部各部分之间的关系及本文件与
其它文件关系等。History 是修改历史记录列表,每条修改记录应包括修改日期、修改
者及修改内容简述

3、结构体/类注释

示例:

/**
 * @brief 用户信息集合
 */
struct UserInfo
{
};

4、接口注释

示例:

/**
 * @brief 查询用户信息
 * @param username 用户名
 * @return 用户信息
 */
UserInfo queryUserInfo(const std::string& username);

5、变量注释

示例:

int age = 0; /* 年龄 */

四、设计规范

每个 C/C++ 程序通常分为两个文件。一个文件用于保存程序的声明(declaration),称为头文件。另一个文件用于保存程序的实现(implementation),称为定义(definition)文件。

C/C++ 程序的头文件通常以 “.h” 为后缀,C 程序的定义文件以 “.c” 为后缀,C++ 程序的定义文件通常以 “.cpp/.cc” 为后缀。

1、 头文件的结构

  • 为了防止头文件被重复引用,应当在头文件的第一行添加 #pragma once,也可以用 ifndef/define/endif 结构产生预处理块
  • 用 #include <filename.h> 格式来引用标准库的头文件
    编译器将在标准库目录搜索,该目录保存在系统的环境变量中
  • 用 #include \“filename.h” 格式来引用非标准库的头文件
    编译器将在当前的工作目录搜索,如果找不到会到标准库目录搜索
  • 头文件中只存放声明,而不存放定义
#prama once             // 防止头文件被重复包含

#include <stdio.h>	    // 引用标准库的头文件
#include "myheader.h"   // 引用非标准库的头文件

void Function(...);    // 全局函数声明

struct ClassName {		// 类结构声明
	...
};

2、定义文件的结构

定义文件有两部分内容:
对头文件的引用
程序的实现体(包括数据和代码)

#include "myheader.h" // 引用头文件

// 全局函数的实现
void Function(...) {
	...
}

// 类成员函数的实现
void ClassName::Fun(...) {
	...
}

3、声明/定义的位置

规范:宏/枚举/变量/接口的声明和定义需要就近原则,能不跨文件就不跨文件。
原因:使得代码更加内聚,提升代码阅读的便利性。
示例:

在类DbMgr中使用了宏定义:#define QUEYR_OK 1
  • 如果该宏只在源文件DbMgr.cpp中使用,则宏定义放在DbMgr.cpp中。
  • 如果该宏仅仅作为返回值透露到外部模块,则宏定义放在DbMgr.h中。
  • 如果该宏在其他若干业务中频繁使用,则宏定义放在公共的业务枚举定义文件中(可能如:enum_def.h)。

4、结构体(struct) or 类(class)?

规范:当定义的类型只是数据的集合且内部无复杂的处理逻辑时选择用struct,反之如果更注重行为的封装则选择class。
原因:struct存在于栈上,用完即销毁。 注意: 由于栈有容量限制,避免在struct中存放超大量的值类型。
示例:

struct UserInfo
{
    UserInfo() : age(0), sex(0) {}
 
    std::string username;
    int age;
    int sex;
};
class Grade
{
public:
    std::vector<UserInfo> queryUserInfoList(const std::string& username);
};

5、单文件(.hpp) or 多文件(.h,.cpp) ?

规范:当模块只是一些信息的集合且无复杂内部逻辑可以使用.hpp,反之使用多文件方式。
原因:模块逻辑复杂时,会经常变动,如果引用的外部模块多而使用.hpp时,编译时间会变长。
示例:
单文件user_info.hpp

#pragma once
#include <string>
 
struct UserInfo
{
    UserInfo() : age(0), sex(0) {}
 
    std::string username;
    int age;
    int sex;
};

多文件grade.h、grade.cpp

#pragma once
#include "user_info.h"
 
class Grade
{
public:
    std::vector<UserInfo> queryUserInfoList(const std::string& username);
};
#include "grade.h"
 
std::vector<UserInfo> Grade::queryUserInfoList(const std::string& username)
{
    return std::vector<UserInfo>{};
}

6、单例类

规范:把构造函数声明为私有。
原因:基于单例的定义,不允许类型不受控制的实例化。
示例:
头文件DbMgr.h

#pragma once
 
class DbMgr
{
private:
    DbMgr();
 
public:
    static DbMgr& getInstance();
};

源文件DbMgr.cpp

DbMgr::DbMgr() {}
 
DbMgr& DbMgr::getInstance()
{
    static DbMgr s_instance;
    return s_instance;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值