当前位置: 首页 > news >正文

代码风格指南

Google 开源项目风格指南——中文版

https://zh-google-styleguide.readthedocs.io/en/latest/contents.html

C++风格指南

1. 头文件

1.1 给需要被导入 (include) 但不属于头文件的文件设置为 .inc 扩展名, 并尽量避免使用.

.inc 文件:是 “include” 的缩写,不是标准的 .h 头文件,但也会在代码中通过 #include 导入。

它通常用于 代码片段,比如:

  • 重复定义的结构体初始化代码
  • 特定模块的一段配置或模板代码
  • 宏实现

不应该包含函数声明或外部接口,而是被视为某种“嵌入性代码片段”。

// file: register_map.inc
REG(UART0, 0x1000)
REG(UART1, 0x1010)
REG(SPI0,  0x1020)// file: device_map.cpp
#define REG(name, addr) init_device(#name, addr);
#include "register_map.inc"
#undef REG

.inc 是为特殊 include 场景保留的临时文件扩展名,提示开发者“这是片段代码”,但为避免混乱和维护成本,应该慎用。

1.2 头文件应该自给自足 (self-contained, 也就是可以独立编译), 并以 .h 为扩展名.

一个 .h 头文件应该包含它自己需要的所有依赖,比如:

  • 需要的其他头文件(如 <string>、自定义类型的定义等)
  • 宏、前向声明等

也就是说,只 include 它本身,不依赖其他文件,也应该能单独通过编译(比如放进一个测试 cpp 文件里去编译)

1.3 头文件

C++头文件的作用是声明接口,供其他源文件(.cpp)使用。头文件不应该包含实现细节,而应该专注于对外公开的接口定义

1.头文件里应放置的内容
内容示例/说明
类的声明与定义包括成员函数声明、成员变量声明
结构体/枚举声明struct, enum class, enum
函数声明(声明,不是实现)void foo();
宏定义(只在必要时)#define PI 3.14(不推荐多用)
常量声明(推荐 constexprconstexpr int MAX = 100;
模板声明或定义模板必须定义在头文件中
内联函数定义(必要时)inline int add(int a, int b) { return a + b; }
命名空间namespace mylib { ... }
类型别名(typedef, usingusing String = std::string;
头文件保护(Include Guard)#ifndef HEADER_H,或者 #pragma once
2.不该放在头文件中的内容
内容原因
函数实现(除非是模板/内联)应放在 .cpp 文件中
变量定义(除非是 constconstexpr会导致重复定义,链接错误
复杂宏或调试宏污染命名空间,难维护,建议放 .inc.cpp
using namespace std;污染命名空间,影响所有包含它的文件
1.4 头文件防护符的格式是: < 项目>_< 路径>_< 文件名>_H_ .
1.5 不要依赖间接导入

在使用某个类型、函数或宏时,应该自己显式 #include 它所在的头文件,而不是依赖别的头文件帮你间接引入。

你用到什么,就自己 include 什么,不要假设别人帮你 include 了。

1.6 尽量避免使用前向声明. 应该导入你所需的头文件。

当你需要使用某个类型的完整定义时,不要用“前向声明”来省事,而是应该直接 #include 对应的头文件。

前向声明是告诉编译器“这个类型将会被定义,但现在我只告诉你它的名字”,而不包含其真正的定义。例如:

class B;  // 前向声明
void FuncInB();  // 前向声明
extern int variable_in_b;  // 前向声明
ABSL_DECLARE_FLAG(flag_in_b);  // 前向声明

它通常用于:

  • 指针或引用成员变量的声明(不需要知道类的全部内容)
  • 减少头文件依赖,加快编译速度
1.7 不要内联超过 10 行的函数
1.8 #include 的路径及顺序:配套的头文件, C 语言系统库头文件, C++ 标准库头文件, 其他库的头文件, 本项目的头文件.

头文件的路径应相对于项目源码目录, 不能出现 UNIX 目录别名 (alias) . (当前目录) 或 … (上级目录).

假设你项目结构如下:

google-awesome-project/
└── src/└── base/│     └── logging.h└──	util/└── foo.cc
✅ 推荐写法(规范):

src/util/foo.cc 中:

#include "base/logging.h"
❌ 不推荐写法(违反规范):
#include "../base/logging.h"   

虽然文件物理上是这么相对布局的,但 Google C++ 风格明确指出:

路径应相对于项目源码根目录(如 src/),不要使用 ... 目录别名。

假设你是这样设置 include path 的:

如果你在 CMake 或 g++/clang++ 里设置了:

-Igoogle-awesome-project/src

那么这个头文件引用是合法且推荐的:

#include "base/logging.h"

假设你在写 dir/foo.cc,它实现或测试的是 dir2/foo2.h,应该这样引入头文件:

#include "dir2/foo2.h"  // 1. 你实现或测试的头文件// 2. 空一行#include <unistd.h>     // 3. C 系统头文件(如 POSIX 标准)
#include <stdlib.h>     //    使用 .h 扩展名// 4. 空一行#include <algorithm>    // 5. C++ 标准库头文件(无扩展名)
#include <vector>// 6. 空一行#include "gtest/gtest.h"    // 7. 其他三方库的头文件// 8. 空一行#include "my_project/utils/log.h"   // 9. 本项目其他头文件

每个分组内部的导入语句应该按字母序排列.

2.作用域

2.1 命名空间
  1. 将代码放入命名空间中:

    • 除了极少数特殊情况(如 main() 函数、顶层宏、全局配置等),你应该始终使用命名空间来包裹代码,避免命名冲突。

    • 比如:

      namespace myproject {class Widget {
      public:void Draw();
      };}  // namespace myproject
      
  2. 不要使用 using namespace xxx;

    • 禁止写:

      using namespace std;   // ❌ 禁止
      
    • 原因:容易引发命名冲突,污染全局命名空间,让代码维护困难、阅读不清晰,尤其在头文件中更危险。

  3. 不要使用内联命名空间 (inline namespace):

    • 内联命名空间用于版本控制,如:

      inline namespace v1 {void foo();
      }
      
    • 禁止原因:这在大型项目中会让接口版本混淆、不透明,难以维护,不如手动明确命名。

    • 允许其成员被自动“提升”到外部命名空间作用域中,让使用者无需明确指定版本号。如:

      假设你维护一个库 mylib,现在你发布了第一个版本:

      namespace mylib {
      inline namespace v1 {void greet();  // 函数 v1 版本
      }
      }
      

      用户使用:

      mylib::greet();  // ✅ 不需要写 mylib::v1::greet()
      

      它背后实际调用的是:

      mylib::v1::greet();
      

      之后你发布了第二个版本:

      namespace mylib {
      inline namespace v2 {void greet();  // 新版本的 greet
      }
      }
      

      旧代码不需要改动:

      mylib::greet();  // ✅ 自动指向 v2 版本
      

      而如果有人确实要用旧版本:

      mylib::v1::greet();  // ✅ 仍然能用
      
2.2 内部链接:放入匿名命名空间 (unnamed namespace)或声明为 static
2.3 局部变量:应该尽可能缩小函数变量的作用域 (scope), 并在声明的同时初始化
2.4 禁止使用 静态储存周期 (static storage duration) 的变量, 除非它们可以 平凡地析构 (trivially destructible).
2.5 函数的局部静态变量可以动态地初始化 (dynamic initialization) . 除了少数情况外, 不推荐动态初始化静态类成员变量或命名空间内的变量.
类型初始化时间例子特点
静态初始化编译期或加载期(编译器能决定)int x = 0;不需要执行函数或复杂逻辑
动态初始化程序运行时std::string s = getConfig();需要执行函数、构造函数等逻辑

C++11 保证函数中 static 变量的动态初始化是线程安全的

const std::string& get_config() {static std::string config = load_config();  // 安全、延迟初始化return config;
}
2.6 thread_local 变量

thread_local 是 C++11 引入的关键字,用于定义 每个线程拥有独立副本 的变量。

thread_local int counter = 0;
  • 每个线程都维护自己的 counter,互不影响。
  • 常用于缓存、日志缓冲、统计计数器等场景。

“必须使用编译期常量初始化”

thread_local int x = 42;  // ✅ OK,42 是编译期常量
thread_local std::string s = "abc"; // ❌ 不可以,涉及构造函数 → 动态初始化
  • 原因是:动态初始化的 thread_local 变量存在初始化顺序和性能问题,容易出错。
  • 多线程中,thread_local 的动态初始化可能发生在不确定的时间点、甚至多次初始化(不同线程),会导致逻辑错误或开销不可控。

“必须使用 ABSL_CONST_INIT 属性”

#include "absl/base/attributes.h"ABSL_CONST_INIT thread_local int x = 0;  // ✅ 强制告知:x 使用编译期常量初始化
  • ABSL_CONST_INIT 是 Google Abseil 库的宏,标记变量应该使用静态常量初始化。
  • 编译器会帮助检查是否违反这一规则,防止误用动态初始化

“优先采用 thread_local,而非其他定义线程内局部数据的方法”

  • 有人可能用 pthread_setspecific、TLS API、线程 ID 映射等手动管理线程本地存储,代码复杂且容易错。
  • 相比之下,thread_local 更安全、更简洁,推荐优先使用。

3.类

3.1 构造函数 (constructor) 中不得调用虚函数 (virtual method). 不要在没有错误处理机制的情况下进行可能失败的初始化
推荐做法:使用工厂函数、Init 方法等替代构造逻辑
方法一:使用工厂函数返回 std::optional / StatusOr
class FileReader {
public:static std::optional<FileReader> Create(const std::string& filename) {FILE* f = fopen(filename.c_str(), "r");if (!f) return std::nullopt;return FileReader(f);}// ... 其他成员函数 ...private:explicit FileReader(FILE* f) : file_(f) {}FILE* file_;
};
方法二:用 Init 分离初始化逻辑
class FileReader {
public:FileReader() : file_(nullptr) {}bool Init(const std::string& filename) {file_ = fopen(filename.c_str(), "r");return file_ != nullptr;}private:FILE* file_;
};
3.2 不要定义隐式类型转换. 定义类型转换运算符和单个参数的构造函数时, 请使用 explicit 关键字

在构造函数前加 explicit

struct MyInt {explicit MyInt(int x) { value = x; }int value;
};void print(MyInt m);int main() {print(42);  // ❌ 编译错误:不能隐式转换print(MyInt(42));  // ✅ 明确转换
}

同理,对于类型转换运算符:

struct A {explicit operator bool() const { return true; }
};

这样写可以避免在布尔上下文中被误用为 if (a) 这样的代码

3.3 类的公有接口必须明确指明该类是可拷贝的、仅可移动的、还是既不可拷贝也不可移动的.

你定义一个类时,必须明确表明它是否支持拷贝和移动操作。如果你想让别人能复制或移动这个类的对象,就必须明确地支持;如果你不想支持,也应该明确禁止。不能模棱两可地“默认让编译器决定”。

设计意图要做的事
可拷贝明确 = default 拷贝构造与赋值运算符
仅可移动显式 = delete 拷贝操作,= default 移动操作
拷贝和移动都不允许全部 = delete
3.4 只能用 struct 定义那些用于储存数据的被动对象. 其他情况应该使用 class.
3.5 如果可以给成员起一个有意义的名字, 应该用结构体而不是数对 (pair) 或元组 (tuple).
3.6 通常情况下, 组合 (composition) 比继承 (inheritance) 更合适. 请使用 public 继承.
3.7 谨慎使用运算符重载 (overload). 禁止自定义字面量 (user-defined literal)

自定义字面量(User-defined Literals) 是 C++11 引入的一种语法扩展,允许你为自定义类型定义 带特殊后缀的常量值,看起来就像是对数字、字符串等原始数据加了“单位”或“标签”。

#include <iostream>constexpr long double operator"" _km(long double x) {return x * 1000;  // 转换为米
}int main() {auto distance = 3.5_km;  // 实际 distance = 3500std::cout << distance << " meters\n";
}

这个 _km 后缀就是你自己定义的字面量,允许你写出像 3.5_km 这样的代码,让数值变得更“人类友好”。

3.8 类的 所有数据成员应该声明为私有 (private), 除非是常量. 这样做可以简化类的不变式 (invariant) 逻辑, 代价是需要增加一些冗余的访问器 (accessor) 代码 (通常是 const 方法).

在 Google Test 中,有时例外:可以用 protected.

Google Test 要求你的测试夹具类的测试函数(即 TEST_F(...) 内部)访问夹具的成员变量。如果成员变量是 private,这些测试代码无法访问它。

所以,在测试类的声明和使用都在同一个 .cc 文件中时,Google 的规范允许你把数据成员设成 protected,方便测试函数访问。

但如果测试类定义在 .h 文件中 ➜ 不允许这样做

如果你把测试夹具类放在头文件里(例如可能多个测试文件会用到这个类),那就要恢复正常封装规则,把成员设为 private

为什么?

  • 因为 .h 文件是公共接口,对整个项目暴露;
  • 如果成员设为 protected,别人可以在外部继承并访问;
  • 这打破了封装性,破坏了良好设计。
3.9 声明次序

类的定义通常以 public: 开头, 其次是 protected:, 最后以 private: 结尾.

在各个部分中, 应该将相似的声明分组, 并建议使用以下顺序:

  1. 类型和类型别名 (typedef, using, enum, 嵌套结构体和类, 友元类型)

  2. (可选, 仅适用于结构体) 非静态数据成员

  3. 静态常量

  4. 工厂函数 (factory function)

  5. 构造函数和赋值运算符

  6. 析构函数

  7. 所有其他函数 (包括静态与非静态成员函数, 还有友元函数)

  8. 所有其他数据成员 (包括静态和非静态的)

4.函数

4.1 我们倾向于按值返回,否则按引用返回。避免返回指针,除非它可以为空.
4.2 我们倾向于编写简短, 凝练的函数.
4.3 使用函数重载时,必须确保“调用处”一眼就能看出调用的是哪个重载版本,而不需要读者反复查参数类型或翻代码去猜。否则就该避免重载,改为用不同的函数名(如 fromIntfromString)来表达意图。
void Print(int count);
void Print(std::string_view message);Print(42);           // 很明显是调用 Print(int)
Print("hello");      // 很明显是调用 Print(std::string_view)

这里调用点非常清晰,不会引起歧义。

4.4 只允许在非虚函数中使用缺省参数, 且必须保证缺省参数的值始终一致.一般推荐用函数重载代替缺省参数,除非默认参数真的能提升代码可读性
4.5 只有在常规写法 (返回类型前置) 不便于书写或不便于阅读时使用返回类型后置语法.
  • 常规写法:函数声明时,返回类型写在函数名前面,比如

    int foo();
    
  • 返回类型后置语法(主要是 C++11 引入的尾置返回类型写法)是把返回类型写在参数列表后面,用 -> 指明返回类型,比如

    auto foo() -> int;
    

在大多数情况下,推荐用传统的写法(返回类型前置),因为它更常见,也更易懂。只有在那种情况下,比如返回类型特别复杂或依赖于模板参数,导致前置写法难写或难读时,才使用后置语法,这样写更清晰。

当返回类型依赖于模板参数时,用后置语法更直观:

template<typename T, typename U>
auto add(T t, U u) -> decltype(t + u) {return t + u;
}

5.来自 Google 的奇技

5.1 动态分配出的对象最好有单一且固定的所有主, 并通过智能指针传递所有权.
5.2 使用 cpplint.py 检查风格错误.

6.其他 C++ 特性

6.1 右值引用
1.只在定义移动构造函数和移动赋值操作符时使用右值引用
  • 右值引用(T&&)主要用于实现 移动构造函数移动赋值操作符,即当你想“搬走”一个对象内部资源而不是复制它时用。
class MyClass {
public:MyClass(MyClass&& other);            // 移动构造函数,参数是右值引用MyClass& operator=(MyClass&& other); // 移动赋值操作符,参数是右值引用
};
  • 右值引用最适合这两个地方,通常不要随意在其他函数参数里使用右值引用。

2. 不要使用 std::forward 函数
  • std::forward 是用在模板和完美转发场景里的,用来“完美转发”参数(保持参数的左值/右值属性)。
  • 在移动构造函数和移动赋值中,不需要用 std::forward,因为你已经明确知道是右值引用了,直接用 std::move 就可以。

3. 你可能会使用 std::move 来表示“移动而非复制”
  • std::move 是一个强制转换,表示“把这个左值变成右值引用”,从而触发移动语义。
  • 比如把资源从一个对象“搬走”而不是复制一份:
std::string s1 = "Hello";
std::string s2 = std::move(s1);  // s1的内容被移动到s2,s1变为空或无效状态
6.2 若要用好函数重载,最好能让读者一看调用点(call site)就胸有成竹,不用花心思猜测调用的重载函数到底是哪一种。
6.3 我们不允许使用缺省函数参数,少数极端情况除外。尽可能改用函数重载。
6.4 我们不允许使用变长数组和 alloca().
特性是否允许原因推荐替代
VLA (int a[n])❌ 禁止非标准、不安全、不可控栈使用std::vector<int> a(n);
alloca()❌ 禁止非标准、栈风险大、不可调试std::vector 或智能指针管理堆内存
6.5 我们允许合理的使用友元类及友元函数.
6.6 我们不使用 C++ 异常.

不是异常不好,而是:

  • 现有代码大量不支持;
  • 与老代码不兼容;
  • 修改成本太高;
  • 替代手段已经够用;
  • 希望开源项目能内外复用。

Google 为了替代 C++ 中的异常机制,设计并广泛使用了 基于返回值的错误处理模式.

6.7 我们禁止使用 RTTI.
6.8 使用 C++ 的类型转换, 如 static_cast<>(). 不要使用 int y = (int)x 或 int y = int(x)等转换方式;
6.9 只在记录日志时使用流.其他地方一律不用流,优先使用格式化函数。
不推荐一般使用 C++ 流的原因:
  1. 效率低
    • C++ 流是面向对象 + 虚函数机制的,性能远低于 printf 风格或 absl::StrFormat 等现代库。
  2. 可读性差
    • 流式拼接往往不如格式字符串直观清晰,尤其对于复杂格式化输出。
  3. 易错且难调试
    • 类型推导和重载太灵活,容易出现隐式转换或意外格式。
  4. 国际化困难
    • 流不支持本地化格式字符串,而格式函数更适合国际化(i18n)。
6.10 对于迭代器和其他模板对象使用前缀形式 (++i) 的自增, 自减运算符.
6.11 我们强烈建议你在任何可能的情况下都要使用 const. 此外有时改用 C++11 推出的 constexpr 更好。
1. 强烈建议尽可能使用 const
  • const 修饰符表示变量、函数参数或成员函数在使用过程中不会被修改。
  • 它可以帮助:
    • 防止意外修改,增强代码安全性和可靠性。
    • 提升代码可读性,让别人一眼看出哪些数据是只读的。
    • 启用编译器更多优化
    • 帮助接口设计,明确哪些函数不修改对象状态(const成员函数)。

2. 适当使用 constexpr
  • constexpr 是 C++11 新引入的关键字,用于指示表达式或函数能在编译期计算。
  • const 不同,constexpr 表示的是编译期常量,能带来更多的性能提升和更安全的代码。
6.12 在 C++11 里,用 constexpr 来定义真正的常量,或实现常量初始化。
6.13 整型
1. 默认只使用 int
  • 在代码中默认使用 int 类型来表示整数。
  • int 类型通常是性能和可读性之间的良好平衡。
2. 需要特定大小时,使用 <stdint.h> 中的精确整型
  • 如果程序中需要指定整数大小(比如网络协议、文件格式、跨平台兼容等),使用 <stdint.h> 里的类型:
    • int16_t(16位有符号整数)
    • int32_t(32位有符号整数)
    • int64_t(64位有符号整数)
    • 以及对应的无符号类型 uint16_t, uint32_t, uint64_t
3. 当变量可能超过 2³¹ (2GiB) 时,使用 64 位类型
  • 如果你的变量可能存储超过 2^31 的值,就使用 int64_t 或者无符号的 uint64_t
4. 注意计算过程中的溢出
  • 即使变量的最终值不会超过 int 的范围,但在计算过程中(比如乘法、累加等),可能会产生溢出。
  • 如果不确定,建议直接使用更大的类型(比如 int64_t),以避免隐患。
6.14 代码应该对 64 位和 32 位系统友好.
方面注意事项推荐做法
打印避免格式符错误,使用 <inttypes.h>使用 PRId64 等标准宏
比较避免有符号和无符号混用,避免隐式转换明确类型,使用固定宽度类型
结构体对齐跨平台可能差异,影响大小和字段偏移明确对齐规则,避免依赖平台默认对齐
6.15 使用宏时要非常谨慎, 尽量以内联函数, 枚举和常量代替之.
宏用途推荐替代优点
常量定义constconstexpr类型安全,调试友好
简单函数inline 函数类型检查,避免多次求值,易维护
枚举常量enumenum class类型安全,命名空间,易读
  1. 传统枚举 (enum)
enum Color {Red,    // 默认值从0开始Green,  // 1Blue    // 2
};Color favorite = Green;

特点

  • 整型常量,默认从 0 开始递增。
  • 所有枚举值共享同一作用域(全局),容易与其他符号冲突。
  • 可隐式转换为 int,不够类型安全。

  1. 枚举类 (enum class) — C++11 引入,推荐使用
enum class Shape {Circle,Square,Triangle
};Shape s = Shape::Circle;

特点

  • 枚举值作用域限制在枚举类型内部,使用时需加前缀 Shape::,避免命名冲突。
  • 不能隐式转换为整型,类型安全。
  • 可指定底层类型:
enum class Status : uint8_t {OK = 0,Error = 1,Unknown = 255
};

  1. 宏替代示例
// 宏定义(不推荐)
#define STATUS_OK 0
#define STATUS_ERROR 1// 替代用 enum class
enum class Status {OK = 0,Error = 1
};
6.16 指针使用 nullptr,字符使用 ‘\0’ (而不是 0 字面值)。
6.17 尽可能用 sizeof(varname) 代替 sizeof(type).

变量类型如果发生变化,sizeof(varname) 会自动更新,无需额外修改。

6.18 用 auto 绕过烦琐的类型名,只要可读性好就继续用,别用在局部变量之外的地方。
6.19 你可以用列表初始化。
int x{5};          // 列表初始化基本类型
std::vector<int> v{1, 2, 3, 4};  // 初始化容器struct Point {int x;int y;
};Point p{10, 20};   // 初始化结构体
6.20 适当使用 lambda 表达式。当 lambda 将转移当前作用域时,首选显式捕获。
int x = 10;
int y = 20;// 隐式捕获(全部按值捕获)
auto lambda1 = [=]() {return x + y;
};// 显式捕获
auto lambda2 = [x, y]() {return x + y;
};
6.21 不要使用复杂的模板编程
6.22 只使用 Boost 中被认可的库

Boost 是一个非常知名且广泛使用的 C++ 开源库集合,涵盖了许多实用功能和工具。

6.23 适当用 C++11(前身是 C++0x)的库和语言扩展,在贵项目用 C++11 特性前三思可移植性。

7.命名约定

7.1 函数命名, 变量命名, 文件命名要有描述性; 少用缩写.
7.2 文件名要全部小写, 可以包含下划线 (_) 或连字符(-), 依照项目的约定. 如果没有约定, 那么“_”更好.
7.3 类型名称的每个单词首字母均大写, 不包含下划线: MyExcitingClass, MyExcitingEnum.
7.4 变量 (包括函数参数) 和数据成员名一律小写, 单词之间用下划线连接. 类的成员变量以下划线结尾, 但结构体的就不用, 如: a_local_variable, a_struct_data_member, a_class_data_member_.
7.5 声明为 constexpr 或 const 的变量, 或在程序运行期间其值始终保持不变的, 命名时以“k”开头, 大小写混合.
7.6 常规函数使用大小写混合, 取值和设值函数则要求与变量名匹配: MyExcitingFunction(), MyExcitingMethod(), my_exciting_member_variable(), set_my_exciting_member_variable().
7.7 命名空间以小写字母命名. 最高级命名空间的名字取决于项目名称.
7.8 枚举的命名应当和常量 或宏 一致: kEnumName 或是 ENUM_NAME.
7.9 你并不打算使用宏, 对吧? 如果你一定要用, 像这样命名: MY_MACRO_THAT_SCARES_SMALL_CHILDREN

8.注释

8.1 使用 // 或 /* */, 统一就好.
8.2 在每一个文件开头加入版权公告。

1.法律公告和作者信息

2.文件内容

8.3 每个类的定义都要附带一份注释, 描述类的功能和用法, 除非它的功能相当明显
8.4 函数声明处的注释描述函数功能; 定义处的注释描述函数实现.
8.5 通常变量名本身足以很好说明变量用途. 某些情况下, 也需要额外的注释说明.
8.6 对于代码中巧妙的, 晦涩的, 有趣的, 重要的地方加以注释.
8.7 注意标点, 拼写和语法; 写的好的注释比差的要易读的多.
8.8 对那些临时的, 短期的解决方案, 或已经够好但仍不完美的代码使用 TODO 注释.
8.9 通过弃用注释(DEPRECATED comments)以标记某接口点已弃用.

9.格式

9.1 每一行代码字符数不超过 80.
9.2 尽量不使用非 ASCII 字符, 使用时必须使用 UTF-8 编码
9.3 只使用空格, 每次缩进 2 个空格.
9.4 返回类型和函数名在同一行, 参数也尽量放在同一行, 如果放不下就对形参分行, 分行方式与函数调用 一致.
9.5 Lambda 表达式对形参和函数体的格式化和其他函数一致; 捕获列表同理, 表项用逗号隔开.
9.6 要么一行写完函数调用, 要么在圆括号里对参数分行, 要么参数另起一行且缩进四格. 如果没有其它顾虑的话, 尽可能精简行数, 比如把多个参数适当地放在同一行里.
9.7 您平时怎么格式化函数调用, 就怎么格式化列表初始化
9.8 倾向于不在圆括号内使用空格. 关键字 if 和 else 另起一行.
9.9 switch 语句可以使用大括号分段, 以表明 cases 之间不是连在一起的. 在单语句循环里, 括号可用可不用.空循环体应使用 {} 或 continue.
9.10 句点或箭头前后不要有空格. 指针/地址操作符 (*, &) 之后不能有空格.
9.11 如果一个布尔表达式超过标准行宽, 断行方式要统一一下
9.12 不要在 return 表达式里加上非必须的圆括号.
9.13 用 =, () 和 {} 均可.
9.14 预处理指令不要缩进, 从行首开始
9.15 访问控制块的声明依次序是 public:, protected:, private:, 每个都缩进 1 个空格.
9.16 构造函数初始化列表放在同一行或按四格缩进并排多行.
9.17 命名空间内容不缩进
9.18 水平留白的使用根据在代码中的位置决定. 永远不要在行尾添加没意义的留白
9.19 垂直留白越少越好

一张图总结Google C++编程规范(Google C++ Style Guide)

在这里插入图片描述

C/C++ 各种代码风格的对比和总结

http://www.xdnf.cn/news/683533.html

相关文章:

  • 聚焦北京央美备考画室:探寻实力之巅
  • 码蹄集——圆周率II、三个非负整数
  • PCB设计自检表
  • 基于心理健康与数字行为数据的多维度分析
  • JAVA运算符详解
  • Oracle向PG转移建议以及注意点
  • 57页 @《人工智能生命体 新启点》中國龍 原创连载
  • IvorySQL 核心技术解读:双 Parser 架构如何定义数据库兼容性?
  • python训练营打卡第36天
  • 竞赛小算法总结(二):gcdlcm,拓展欧几里得线性同余,逆元(含代码详解)
  • AE的ai图层导到Ai
  • spring4第2课-ioc控制反转-依赖注入,是为了解决耦合问题
  • WIN10 安装dify ollama搭建工作流agent
  • 两种主流检索技术:BM25(基于关键词匹配)和向量相似度检索
  • LVGL(Flex布局)
  • Docker修改镜像存放位置
  • qiankun 子应用怎样通过 props拿到子应用【注册之后挂载之前】主应用中发生变更的数据
  • vue2轮播图组件
  • 计算机网络实验课(二)——抓取网络数据包,并实现根据条件过滤抓取的以太网帧,分析帧结构
  • 如何检查液质联用仪LCMS的真空度
  • 提升前端性能:减少DOM操作
  • 在线项目管理工具对比:Trello、Worktile等20款软件测评
  • Java的Spring Cloud生态中实现SSE(Server-Sent Events)服务端实践
  • YoloV11改进策略:卷积篇-风车卷积-即插即用
  • 代码随想录算法训练营第60期第四十九天打卡
  • day05-常用API(二):Lambda、方法引用详解
  • Python装饰器与异常捕获的高级用法详解
  • 基于 STM32 的农村污水处理控制系统设计与实现
  • @vue/composition-api
  • uniapp-商城-72-shop(5-商品列表,购物车实现回顾)