美文网首页
Google c++ style 学习

Google c++ style 学习

作者: Little熊猫 | 来源:发表于2018-05-04 18:48 被阅读0次

最近在整理c++代码,顺便参考谷歌的c++编译规范,总结了几点是我们日常碰到比较多的。

一 宏使用

C语言写多了容易喜欢使用宏来定义常量或者代码,而c++中就不建议这样做了。
比如使用define定义Inline代码的话,c++中建议直接使用inline函数的形式
使用define 定义常量,c++则建议使用const来修饰常变量。
宏还有的其他用法比如条件编译什么的,在C++中使用宏之前都想一下是否可以使用其他方法进行替代。
如果要使用宏的话,遵循下面几个方法:
不要在.h文件中使用宏
在使用的代码前使用#define,用完后使用#undef
不要使用#undef替换存在的宏,使用其他的名字
不要使用##去生成function class variable名字
Try not to use macros that expand to unbalanced C++ constructs, or at least document that behavior well.
比如在art代码中使用了const来修饰常变量,而不是定义宏

constexpr u1 kVisibilityBuild   = 0x00;
constexpr u1 kVisibilityRuntime = 0x01;
constexpr u1 kVisibilitySystem  = 0x02;

二 类型转换

C语言转换比较简单,比如int y = (int)x;这样直接转换,而c++针对不同类型的转换使用不同的方法:
const_cast:const类型转换,一般用于将const/volatile属性去掉或者添加
reinterpret_cast: 任意类型的指针转换

int *r = reinterpret_cast<int*>(&c); // forced conversion

static_catst: 编译过程中进行转换校验,主要转换基本类型或者继承关系类型之间的转换,不太用于指针类型指针类型之间的转换。

int *q = static_cast<int*>(&c); // compile-time error 

dynamic_cast:用于进程对象指针之间或引用之间的转换

// Succeeds for a MyChild object
MyChild *child = dynamic_cast<MyChild*>(base);

三 整型

如果对于变量的size有要求的话建议使用<stdint.h>里面的int16_t, uint32_t,int64_t。当我们使用一般不是很大的数据造成溢出时,使用int比较方便。但是unsigned int不建议使用,当你要使用超过32为的数据是建议使用int64_t或者uint64_t。因为unsigned int往往会造成bug,比如如下:

for (unsigned int i = foo.Length()-1; i >= 0; --i) ...

确保一个数为非负的话不要使用unsigned类型,使用assert进行判断。

四 命名

从一个项目的命名就可以对一个项目的质量做判断,好的软件项目一定会有一个好的命名规则。好的名字包括 函数名 变量名 文件名 类名,能够做到清晰的表达,没有歧义。类型和变量使用名词,函数使用“command” verbs。
通过阅读android的代码可以看出,cpp的代码大部分使用驼峰命名法。

int num_errors; // Good.
int num_completed_connections; // Good

推荐使用上面的例子命名方法,变量没有歧义,表达很清楚,做到一目了然。下面的例子则不推荐,表达歧义,不容易被其他人理解。

int n; // Bad - meaningless.
int nerr; // Bad - ambiguous abbreviation.
int n_comp_conns; // Bad - ambiguous abbreviation.

// Good
// These show proper names with no abbreviations.
int num_dns_connections; // Most people know what "DNS" stands for.
int price_count_reader; // OK, price count. Makes sense.

// Bad!
// Abbreviations can be confusing or ambiguous outside a small group.
int wgc_connections; // Only your group knows what this stands for.
int pc_reader; // Lots of things can be abbreviated "pc".

int error_count; // Good.
int error_cnt; // Bad.

4.1 文件名

文件名使用小写 _ 和-,如果没有特殊的要求的话,优先使用_。
my_useful_class.cc 
my-useful-class.cc
myusefulclass.cc 
myusefulclass_test.cc // _unittest and _regtest are deprecated.

如果头文件包含很多的inline函数的话,可以单独拿出放到-inl.h文件中

url_table.h // The class declaration.
url_table.cc // The class definition.
url_table-inl.h // Inline functions that include lots of code.

4.2 类型名

类型名义大写为开头,每个新的词第一个字母也要大写,不要使用_,比如MyExcitingClass, MyExcitingEnum。

   // classes and structs
class UrlTable { ...
class UrlTableTester { ...
struct UrlTableProperties { ...
// typedefs
typedef hash_map<UrlTableProperties *, string> PropertiesMap;
// enums
enum UrlTableErrors { ...

4.3 变量名

变量名统一使用小写,使用””连接,类中的变量在末尾添加””。

string table_name; // OK - uses underscore.
string tablename; // OK - all lowercase.
string tableName; // Bad - mixed case.

对于class里面的变量

string table_name_; // OK - underscore at end.
string tablename_; // OK.

对于结构体中的变量,跟普通变量命名一样。

struct UrlTableProperties {
string name;
int num_entries;
}

全局变量谷歌没有做特殊要求,如果非要做区分的话可以在前面添加”g_”来区分本地变量

4.4 常量命名

常量名前加”k”,比如kDaysInAWeek

const int kDaysInAWeek = 7;

4.5 函数名

函数首字母大写,每个word的首字母也要大写,如果函数因为error而crash的话,在函数的末尾添加OrDie。

AddTableEntry()
DeleteUrl()
OpenFileOrDie()

如果操作变量的话,最好在函数中添加操作的变量名。比如

class MyClass {
public:
...
int num_entries() const { return num_entries_; }
void set_num_entries(int num_entries) { num_entries_ = num_entries; }
private:
int num_entries_;
};

通过观察可得到,谷歌使用大写驼峰命名函数较为普遍,使用小写加下划线的方式较少。

4.6 枚举命名

枚举的命名跟常量或者宏的规则一样。比如kEnumName 或者
ENUM_NAME

    enum UrlTableErrors {
        kOK = 0,
        kErrorOutOfMemory,
        kErrorMalformedInput,
    };
    enum AlternateUrlTableErrors {
        OK = 0,
        OUT_OF_MEMORY = 1,
        MALFORMED_INPUT = 2,
};

这里面谷歌提到同宏命名法容易出现跟宏命名重复,推荐使用常量的命名方法

4.7 宏命名

谷歌不推荐使用宏命名,如果非要使用的话,同C一样大写加”_”的方式

#define ROUND(x) ...
#define PI_ROUNDED 3.0

4.8 例外
当然也有例外,下面几种情况可以遵循现有代码的规则。

bigopen()
    function name, follows form of open()
uint
    typedef
bigpos
    struct or class, follows form of pos
sparse_hash_map
    STL-like entity; follows STL naming conventions
LONGLONG_MAX
    a constant, as in INT_MAX

五 注释

好的代码就是最好的注释,注释的规范如下:

5.1 注释风格

注释使用//或者//,两种都可以,通过阅读谷歌的代码,//一般用在文件开头license,//用在代码注释中。

5.2 文件注释

文件注释,一般在文件的开头,包括版权信息 作者 和文件内容描述。这个每个公司不大一样,就不详细介绍了

5.2 类注释

类注释描述类的用处和使用方法

// An alloc space is a space where objects may be allocated and garbage collected. Not final as may
// be overridden by a MemoryToolMallocSpace.
class DlMallocSpace : public MallocSpace {

5.3 函数注释

函数注释不要写函数如何实现,而是介绍函数的作用和使用方法,具体到注释中可以添加的内容如下:
1) 输入输出
2) Class里面的函数,如果执行中有使用引用,是否会释放他们
3) 如果函数分配内存,则调用者必须释放
4) 参数是否可以是NULL
5) 函数调用方法是否影响性能
6) 如果函数可重入,如何同步

   // Returns an iterator for this table. It is the client's
// responsibility to delete the iterator when it is done with it,
// and it must not use the iterator once the GargantuanTable object
// on which the iterator was created has been deleted.
//
// The iterator is initially positioned at the beginning of the table.
//
// This method is equivalent to:
// Iterator* iter = table->NewIterator();
// iter->Seek("");
// return iter;
// If you are going to immediately seek to another place in the
// returned iterator, it will be faster to use NewIterator()
// and avoid the extra seek.
Iterator* GetIterator() const;

函数定义出应该有注释,比如如下:

  // Create a DlMallocSpace from an existing mem_map.
  static DlMallocSpace* CreateFromMemMap(MemMap* mem_map, const std::string& name,
                                         size_t starting_size, size_t initial_size,
                                         size_t growth_limit, size_t capacity,
                                         bool can_move_objects);

5.4 变量注释
通过变量名可以得到变量的大部分信息,当然有些情况需要注释来描述变量。
类变量,每个类变量应该有注释描述。如果变量可以是特殊值比如NULL或者-1,在注释中要添加

private:
// Keeps track of the total number of entries in the table.
// Used to ensure we do not go over the limit. -1 means
// that we don't yet know how many entries the table has.
int num_total_entries_;

全局变量:全局变量也要添加注释

// The total number of tests cases that we run through in this regression test.
const int kNumTestCases = 6;

5.5 implementaion 注释

我的理解是操作注释,在函数中,便于别人理解,一些关键性的操作需要添加注释,比如

        if (space->IsImageSpace()) {
          // Image space end is the end of the mirror objects, it is not necessarily page or card
          // aligned. Align up so that the check in ClearCardRange does not fail.
          end = AlignUp(end, accounting::CardTable::kCardSize);
        }
        card_table_->ClearCardRange(space->Begin(), end);

5.6 行注释

如果注释和代码是一行的话,注释应该和代码留有2个空格

// If we have enough memory, mmap the data portion too.
mmap_budget = max<int64>(0, mmap_budget - index_->length());
if (mmap_budget >= data_size_ && !MmapData(mmap_chunk_bytes, mlock))
return; // Error already logged.

如果有多行注释时,最好要对齐

DoSomething(); // Comment here so the comments line up.
DoSomethingElseThatIsLonger(); // Comment here so there are two spaces between
// the code and the comment.
{ // One space before comment when opening a new scope is allowed,
// thus the comment lines up with the following comments and code.
DoSomethingElse(); // Two spaces before line comments normally.
}

5.7 NULL, true/false,1,2,3.. 注释

如果传递 NULL, Boolean 立即数参数到函数是,应该添加注释说明

bool success = CalculateSomething(interesting_value,
10, // Default base value.
false, // Not the first time we're calling this.
NULL); // No callback.

其实还是不建议传这种参数

const int kDefaultBaseValue = 10;
const bool kFirstTimeCalling = false;
Callback *null_callback = NULL;
bool success = CalculateSomething(interesting_value,
kDefaultBaseValue,
kFirstTimeCalling,
null_callback);

5.8 注释注意事项

注释不要有拼写语法错误,一定要表达清楚。比如应该使用“;”的地方使用了“,”

5.9 TODO住址

添加TODO注释 表明当前的code是暂时的,或者临时解决方案,也或者是代码需要后期维护,不完美的代码。
TODO添加你的联系方式,TODO的作用是便于联系作者去fix掉这个TODO项

 //TODO(kl@gmail.com): Use a "*" here for concatenation operator.
// TODO(Zeke) change this to use relations.

5.10 弃用注释

常见的注释使用如下:

// @deprecated
static inline void Set2BE(uint8_t* buf, uint16_t val) {
  *buf++ = (uint8_t)(val >> 8);
  *buf = (uint8_t)(val);
}

六 格式

相对注释 命名更主观的规则,代码的格式则是相对客观,只要按照规定来coding即可。

6.1 行长度

一行最多有80个字符的长度。当然也有例外
例外一:如果注释行包含命令示例或者URL的长度超过80行的话
例外二: #include的头文件超过80行

6.2 非ASCII字符

统一使用UTF-8格式

6.3 空格和TAB符

只能使用空格,一次缩进2个字符。

6.4 函数声明和定义

函数的格式如下:

ReturnType ClassName::FunctionName(Type par_name1, Type par_name2) {
  DoSomething();
  ...
}
ReturnType ClassName::ReallyLongFunctionName(Type par_name1, Type par_name2,
                                             Type par_name3) {
  DoSomething();
  ...
}
ReturnType LongClassName::ReallyReallyReallyLongFunctionName(
    Type par_name1, // 4 space indent
    Type par_name2,
    Type par_name3) {
  DoSomething(); // 2 space indent
  ...
}

如果函数是const的话,const应该跟最后一个参数一行

// Everything in this function signature fits on a single line
ReturnType FunctionName(Type par) const {
  ...
}
// This function signature requires multiple lines, but
// the const keyword is on the line with the last parameter.
ReturnType ReallyLongFunctionName(Type par1,
                                         Type par2) const {
   ...
}

如果参数不被使用的话,在函数定义的时候注释掉变量名

 // Always have named parameters in interfaces.
class Shape {
  public:
    virtual void Rotate(double radians) = 0;
}
// Always have named parameters in the declaration.
class Circle : public Shape {
  public:
    virtual void Rotate(double radians);
}
// Comment out unused named parameters in definitions.
void Circle::Rotate(double /*radians*/) {}

// Bad - if someone wants to implement later, it's not clear what the
// variable means.
void Circle::Rotate(double) {}

6.5 函数调用

函数的调用同函数的定义格式差不多

bool retval = DoSomething(argument1, argument2, argument3);
bool retval = DoSomething(averyveryveryverylongargument1,
                          argument2, argument3);
bool retval = DoSomething(argument1,
                          argument2,
                          argument3,
                          argument4);

if (...) {
  ...
  ...
  if (...) {
    DoSomethingThatRequiresALongFunctionName(
                very_long_argument1, // 4 space indent
                argument2,
                argument3,
                argument4);
}

6.6 条件执行

推荐使用如下这种方式

if (condition) { // no spaces inside parentheses
  ... // 2 space indent.
} else if (...) { // The else goes on the same line as the closing brace.
  ...
} else {
  ...
}

如果执行的代码较短没有else的话推荐如下使用

if (x == kFoo) return new Foo();
if (x == kBar) return new Bar();

除非与if同一行,if后添加{}

if (condition) {
  DoSomething(); // 2 space indent.
}
// Curly braces around both IF and ELSE required because
// one of the clauses used braces.
if (condition) {
  foo;
} else {
  bar;
}

6.7 循环和switch语句

针对switch语句,采用如下格式

switch (var) {
  case 0: { // 2 space indent
    ... // 4 space indent
    break;
  }
  case 1: {
    ...
    break;
  }
  default: {
    assert(false);
  }
}

针对循环使用{}或者continue,不要使用一个分号

while (condition) {
// Repeat test until it returns false.
}
for (int i = 0; i < kSomeNumber; ++i) {} // Good - empty body.
while (condition) continue; // Good - continue indicates no logic.
while (condition); // Bad - looks like part of do/while loop.

6.8 指针和引用表达

  x = *p;
p = &x;
x = r.y;
x = r->y;

在.或者->周围没有空格
在*或者&后面没有空格

// These are fine, space preceding.
char *c;
const string &str;
// These are fine, space following.
char* c; // but remember to do "char* c, *d, *e, ...;"!
const string& str;
char * c; // Bad - spaces on both sides of *
const string & str; // Bad - spaces on both sides of &

6.9 boolean 表达式

&&放在一行的末尾,这种形式比较多见。

if (this_one_thing > this_other_thing &&
    a_third_thing == a_fourth_thing &&
    yet_another && last_one) {
  ...
}

6.10 return 返回值

Return返回值不要带有括号,除非是表达式

return result; // No parentheses in the simple case.
return (some_long_condition && // Parentheses ok to make a complex
        another_condition); // expression more readable.

6.11 变量和数组初始化

初始化使用= 或者()

int x = 3;
int x(3);
string name("Some Name");
string name = "Some Name";

6.12预处理指令

预处理放在行开始处

// Good - directives at beginning of line
if (lopsided_score) {
#if DISASTER_PENDING // Correct -- Starts at beginning of line
  DropEverything();
# if NOTIFY // OK but not required -- Spaces after #
  NotifyClient();
# endif
#endif
  BackToNormal();
}

6.13 类格式

有一点稍微注意一下,public函数在上,往下依次是protected 和Private

class MyClass : public OtherClass {
  public: // Note the 1 space indent!
    MyClass(); // Regular 2 space indent.
    explicit MyClass(int var);
    ~MyClass() {}
    void SomeFunction();
    void SomeFunctionThatDoesNothing() {
    }
    void set_some_var(int var) { some_var_ = var; }
    int some_var() const { return some_var_; }
  private:
    bool SomeInternalFunction();
    int some_var_;
    int some_other_var_;
    DISALLOW_COPY_AND_ASSIGN(MyClass);
};

6.14 构造函数初始化参数列表

构造函数初始化常用下面两种形式

// When it all fits on one line:
MyClass::MyClass(int var) : some_var_(var), some_other_var_(var + 1) {}
或者
// When it requires multiple lines, indent 4 spaces, putting the colon on
// the first initializer line:
MyClass::MyClass(int var)
    : some_var_(var), // 4 space indent
    some_other_var_(var + 1) { // lined up
  ...
  DoSomething();
  ...
}

6.15 namepsace 格式

在namespace里面不要使用缩进

namespace {
void foo() { // Correct. No extra indentation within namespace.
  ...
}
} // namespace

6.16 水平空格

不要在文件结尾添加空格

void f(bool b) { // Open braces should always have a space before them.
...
int i = 0; // Semicolons usually have no space before them.
int x[] = { 0 }; // Spaces inside braces for array initialization are
int x[] = {0}; // optional. If you use them, put them on both sides!
// Spaces around the colon in inheritance and initializer lists.
class Foo : public Bar {
  public:
  // For inline function implementations, put spaces between the braces
  // and the implementation itself.
  Foo(int b) : Bar(), baz_(b) {} // No spaces inside empty braces.
  void Reset() { baz_ = 0; } // Spaces separating braces from implementation.
  ...

循环和条件执行

if (b) { // Space after the keyword in conditions and loops.
} else { // Spaces around else.
}
while (test) {} // There is usually no space inside parentheses.
switch (i) {
for (int i = 0; i < 5; ++i) {
switch ( i ) { // Loops and conditions may have spaces inside
if ( test ) { // parentheses, but this is rare. Be consistent.
for ( int i = 0; i < 5; ++i ) {
for ( ; i < 5 ; ++i) { // For loops always have a space after the
... // semicolon, and may have a space before the
// semicolon.
switch (i) {
  case 1: // No space before colon in a switch case.
  ...
  case 2: break; // Use a space after a colon if there's code after it.

运算符

x = 0; // Assignment operators always have spaces around
// them.
x = -5; // No spaces separating unary operators and their
++x; // arguments.
if (x && !y)
...
v = w * x + y / z; // Binary operators usually have spaces around them,
v = w*x + y/z; // but it's okay to remove spaces around factors.
v = w * (x + z); // Parentheses should have no spaces inside them.

模板和转化

vector<string> x; // No spaces inside the angle
y = static_cast<char*>(x); // brackets (< and >), before
// <, or between >( in a cast.
vector<char *> x; // Spaces between type and pointer are
// okay, but be consistent.
set<list<string> > x; // C++ requires a space in > >.
set< list<string> > x; // You may optionally use
// symmetric spacing in < <.

6.17 空行

代码尽量减少空行,在空行没有详细的定义。从可读性出发,可以适当的添加空行。

相关文章

  • Google c++ style 学习

    最近在整理c++代码,顺便参考谷歌的c++编译规范,总结了几点是我们日常碰到比较多的。 一 宏使用 C语言写多了容...

  • Google C++ Style

    C++规范 类规范构造函数中不调用虚函数,考虑使用Init()或者工厂函数不定义隐式类型转换,对于转换运算符好单参...

  • C++编程风格指南-中文版

    前⾔:本⽂翻译⾃C++ Programming Style Guidelines原⽂地址参考资料:Google机翻...

  • vscode C++ 开发配置 google code styl

    vscode C++ 开发配置 google code style 代码格式插件 ⌘ +⇧+p 输入 instal...

  • Google Style 学习

    头文件 头文件避免多重包含。#ifndef PROJ_PATH_FILE_H_ 能用前置声明就不要使用#inclu...

  • win下VS2015代码风格检查

    目标: 代码符合Google C++ Style Guide。 正文: 1.可以使用Cpplint进行代码风格检测...

  • Google C++ Style 资源记录

    因为工程中用到的google代码非常多,所以C++项目的代码全部使用google的代码风格。记录下资源地址。Goo...

  • python doctring 风格

    Numpy Style Google Style reStructuredText Epytext

  • Coding Style

    Google style

  • Google Style

    Try these tips for refining your search[1] Common words a...

网友评论

      本文标题:Google c++ style 学习

      本文链接:https://www.haomeiwen.com/subject/rdhjrftx.html