[C/C++]风格指南

参考:http://zh-google-styleguide.readthedocs.io/en/latest/contents/


 0. #define保护 ___H_
 1. 初始化所有变量
    int i = f(); //good
    vector<int> v = {1,2}; //good
 2. 保持函数短小精悍
 3. 判断布尔值 if (FALSE != func()) {...
 4. 不要在头文件.h进行数据定义: int x = 0;
 5. 用宏或常量代替数字
 6. 注释格式尽量统一,建议使用“/* …… */7. 严禁使用未经初始化的变量作为右值
 8. 一个函数仅完成一件功能,
    函数返回值是int并作为状态位使用时,return 0表示函数结束或正确返回,return 1表示功能性错误返回, 大于1的值表示错误码
    为简单功能编写函数,
    尽量不要超过40行
    不要设计多用途面面俱到的函数,
    尽量不要编写依赖于其他函数内部实现的函数
    避免设计多参数函数,不使用的参数从接口中去掉
    检查函数所有参数输入的有效性
    使用动宾词组为执行某操作的函数命名
    减少函数本身或函数间的递归调用
    函数的参数顺序为: 输入参数在先(const引用或参值), 后跟输出参数(非const指针)void Foo(const string &in, string *out);
    所有按引用传递的参数必须加上const
 9. 循环体内工作量最小化
 10.避免循环体内含判断语句,应将循环语句置于判断语句的代码块之中
 11.过程/函数中分配的内存,在过程/函数退出之前要释放
 12.过程/函数中分配的内存,在过程/函数退出之前要释放
 13.要防止差1错误
 14.要时刻注意易混淆的操作符。当编完程序后,应从头至尾检查一遍这些操作符,以防止拼写错误
 15.switch语句必须有default分支
 16.不要滥用goto语句
 17.通过代码走读及审查方式对代码进行检查
 18.不应通过“试”来解决问题,应寻找问题的根本原因
 19.不要使用 C 风格类型转换. 而应该使用 C++ 风格.如 static_cast<>(). 不要使用 int y = (int)x 或 int y = int(x) 等转换方式;
 20.除了日志,不要使用<<,使用printf + read/write
 21.对简单数值 (非对象), 两种都无所谓. 对迭代器和模板类型, 使用前置自增 (自减).--i/++i
 22.我们强烈建议你在任何可能的情况下都要使用 const. 此外有时改用 C++11 推出的 constexpr 更好
 23.宏
      不要在.h 文件中定义宏.
      在马上要使用时才进行 #define, 使用后要立即 #undef.
      不要只是对已经存在的宏使用#undef,选择一个不会冲突的名称;
      不要试图使用展开后会导致 C++ 构造不稳定的宏, 不然也至少要附上文档说明其行为.
      不要用 ## 处理函数,类和变量的名字。
 24.整数用 0, 实数用 0.0, 指针用 nullptr 或 NULL, 字符 (串) 用 '\0'.
 25.尽可能用 sizeof(varname) 代替 sizeof(type)
 26.auto 绕过烦琐的类型名,只要可读性好就继续用,别用在局部变量之外的地方
 27.不要使用复杂的模板编程
 28.只使用 Boost 中被认可的库
 29.命名约定
    通用命名规则:函数命名, 变量命名, 文件命名要有描述性; 少用缩写
    文件命名:文件名要全部小写, 可以包含下划线 (_) 或连字符 (-), 依照项目的约定. 如果没有约定, 那么 “_” 更好
    类型命名:所有类型命名 —— 类, 结构体, 类型定义 (typedef), 枚举, 类型模板参数,每个单词首字母均大写
    变量命名:变量 (包括函数参数) 和数据成员名一律小写, 单词之间用下划线连接. 类的成员变量以下划线结尾, 但结构体的就不用, 如: a_local_variable, a_struct_data_member, a_class_data_member_.
    常量命名:声明为 constexprconst 的变量, 或在程序运行期间其值始终保持不变的, 命名时以 “k” 开头, 大小写混合
    函数命名:常规函数使用大小写混合, 取值和设值函数则要求与变量名匹配: MyExcitingFunction(), MyExcitingMethod(), my_exciting_member_variable(), set_my_exciting_member_variable().
 30.注释 /* */ 注意标点, 拼写和语法; 写的好的注释比差的要易读的多
 31.你所提供的注释应当解释代码 为什么 要这么做和代码的目的, 或者最好是让代码自文档化.
 32.TODO 注释
 33.弃用注释 DEPRECATED 
 34.尽量不使用非 ASCII 字符, 使用时必须使用 UTF-8 编码
 35.只使用空格, 每次缩进 2 个空格
 36.if (x == kFoo) return new Foo();
 37.assert(false); 断言
 38.int x = 3;int x(3); int x{ 3 }; string name("Some Name"); string name = "Some Name"; string name{ "Some Name" };
 39.垂直留白:垂直留白越少越好.两个函数定义之间的空行不要超过 2 行, 函数体首尾不要留空行, 函数体中也不要随意添加空行.
 40.char *c; const string &str;
 41.Windows 代码
 42.不要使用匈牙利命名法(比如把整型变量命名成 iNum).使用 Google 命名约定, 包括对源文件使用.cc 扩展名.
 43.Windows 定义了很多原生类型的同义词(YuleFox 注 : 这一点, 我也很反感), 如 DWORD, HANDLE 等等.在调用 Windows API 时这是完全可以接受甚至鼓励的.即使如此, 还是尽量使用原有的 C++ 类型, 例如使用 const TCHAR * 而不是 LPCTSTR.
 44.使用 Microsoft Visual C++ 进行编译时, 将警告级别设置为 3 或更高, 并将所有警告(warnings)当作错误(errors)处理.
 45.不要使用 #pragma once; 而应该使用 Google 的头文件保护规则.头文件保护的路径应该相对于项目根目录(Yang.Y 注 : 如 #ifndef SRC_DIR_BAR_H_, 参考 #define 保护 一节).
 46.除非万不得已, 不要使用任何非标准的扩展, 如 #pragma 和 __declspec.使用 __declspec(dllimport) 和 __declspec(dllexport) 是允许的, 但必须通过宏来使用, 比如 DLLIMPORT 和 DLLEXPORT, 这样其他人在分享使用这些代码时可以很容易地禁用这些扩展.
 47.然而, 在 Windows 上仍然有一些我们偶尔需要违反的规则 :
 48.通常为了利用头文件预编译, 每个每个源文件的开头都会包含一个名为 StdAfx.h 或 precompile.h 的文件.为了使代码方便与其他项目共享, 请避免显式包含此文件(除了在 precompile.cc 中), 使用 / FI 编译器选项以自动包含该文件.
 49.资源头文件通常命名为 resource.h 且只包含宏, 这一文件不需要遵守本风格指南.
 50.#include 的路径及顺序
    dir2/foo2.h (优先位置, 详情如下)
    C 系统文件
    C++ 系统文件
    其他库的 .h 文件
    本项目内 .h 文件

实例

my_useful_class.h

//define保护:___H_
#ifndef CSTYLEGUIDE_MY_USEFUL_CLASS_H_
#define CSTYLEGUIDE_MY_USEFUL_CLASS_H_

// 结构体与类:仅当只有数据成员时使用 struct, 其它一概使用 class.
// 内联函数:只有当函数只有 10 行甚至更少时才将其定义为内联函数.
// 类型转换:使用 C++ 的类型转换, 如 static_cast<>(). 不要使用 int y = (int)x 或 int y = int(x) 等转换方式;
// 宏:不要在 .h 文件中定义宏
// sizeof: 尽可能用 sizeof(varname) 代替 sizeof(type).
// auto: 用 auto 绕过烦琐的类型名,只要可读性好就继续用,别用在局部变量之外的地方
// 模板编程:不要使用复杂的模板编程
// Boost库:只使用 Boost 中被认可的库
// 注释风格:统一使用 //
// 文件注释:不要在 .h 和 .cc 之间复制注释, 这样的注释偏离了注释的实际意义.
// 类注释:
// Iterates over the contents of a GargantuanTable.
// Example:
//    GargantuanTableIterator* iter = table->NewIterator();
//    for (iter->Seek("foo"); !iter->done(); iter->Next()) {
//      process(iter->key(), iter->value());
//    }
//    delete iter;
// 函数:函数声明处的注释描述函数功能; 定义处的注释描述函数实现
class MyUsefulClass
{
 public:
    // 1.类型(包括typedef,using和嵌套的结构体和类)
    // 2.常量
    // 3.工厂函数
    // 4.构造函数 在构造函数中进行初始化操作,不要调用虚函数,也不要在无法报出错误时进行可能失败的初始化
    MyUsefulClass(); // 不在构造函数中做太多逻辑相关的初始化
    // 5.赋值运算符
    // 6.析构函数
    ~MyUsefulClass();
    // 7.其他函数 函数体尽量短小, 紧凑, 功能单一
    // 函数不超过40行
    void set_a_class_data_member(const char *a_class_data_member); // 参数变量
    char* get_a_class_data_member();
    // 引用参数必须const,输入参数必须const,输出参数非const
    void Foo(const string &in, string *out);

 protected:

 private:
    // 8.数据成员 所有数据成员声明为private
    char *a_class_data_member_; // 成员变量
    string class_data_member_;
};

#endif // CSTYLEGUIDE_MY_USEFUL_CLASS_H_

my_useful_class.cc

// my_useful_class.cc
// Copyright(C) 2018.3.13 Version 1.0 ALEX.B.Z
// include头文件顺序
// 在 #include 中插入空行以分割相关头文件, C 库, C++ 库, 
// 其他库的 .h 和本项目内的 .h 是个好习惯
#include "my_useful_class.h" // 主要作用是实现或测试

#include  // C系统文件

#include  // C++系统文件
#include 
#include 

//#include  // 其他库的.h文件
//#include "include_test.h" // 本项目内的.h文件

using std::string;
using std::vector;
using std::map;

// 结构体,成员属性都可以和普通变量一样   
typedef struct MyStruct {
    string name;
    int num_entries;
} my_struct_t;

// 枚举
enum MyEnum {
    kOk = 0,
    kErrorOutMemory,
    kErrorMalformedInput,
};

// 常量命名 "k"开头,大小写混合
const int kDaysInWeek = 7;
// 全局变量 小写,下划线分割 变量声明时进行初始化
string table_name;
//int j = g();
vector<int> v = {1,2};


MyUsefulClass::MyUsefulClass()
{
    // Vector 接收了一个初始化列表。
    vector<string> v{ "foo", "bar" };

    // 不考虑细节上的微妙差别,大致上相同。
    // 您可以任选其一。
    vector<string> v = { "foo", "bar" };

    // 可以配合 new 一起用。
    auto p = new vector<string>{ "foo", "bar" };

    // map 接收了一些 pair, 列表初始化大显神威。
    map<int, string> m = { { 1, "one" }, { 2, "2" } };

    // 初始化列表也可以用在返回类型上的隐式转换。
    vector<int> test_function() { return{ 1, 2, 3 }; }

    // 初始化列表可迭代。
    for (int i : {-1, -2, -3}) {}

    // 在函数调用里用列表初始化。
    void TestFunction2(vector<int> v) {}
    TestFunction2({ 1, 2, 3 });
}

MyUsefulClass::~MyUsefulClass()
{
}

// 函数的输入输出.
// 对类成员函数而言: 函数调用期间对象是否需要保持引用参数, 是否会释放这些参数.
// 函数是否分配了必须由调用者释放的空间.
// 参数是否可以为空指针.
// 是否存在函数使用上的性能隐患.
// 如果函数是可重入的, 其同步前提是什么 ?
// 垂直留白:这不仅仅是规则而是原则问题了: 不在万不得已, 不要使用空行. 
// 尤其是: 两个函数定义之间的空行不要超过 2 行, 函数体首尾不要留空行, 函数体中也不要随意添加空行.
void MyUsefulClass::Foo(const string &in, string *out)
{

}

你可能感兴趣的:(C/C++)