程式碼格式

以下內容參考google C++風格指南

命名

命名規則

名稱要有描述性;少用縮寫。

1
2
3
4
int price_count_reader;  // 無縮寫。
int num_errors;      // "num" 是很常見的縮寫字。
int num_dns_connections;   // 大部份的人都知道 "DNS" 是啥。
int lstm_size;       // "LSTM" 在機器學習領域中是個常用的縮寫字。
1
2
3
4
5
6
7
int n;           // 毫無意義。
int nerr;          // 模稜兩可的縮寫。
int n_comp_conns;      // 模稜兩可的縮寫。
int wgc_connections;     // 只有貴團隊知道是啥意思。
int pc_reader;       // "pc" 有太多可能的解釋了。
int cstmr_id;        // 有刪減若干字母。
FooBarRequestInfo fbri;  // 根本不是個單字。

檔案名

檔案名稱要全部小寫,可以包含底線 () 或減號 (-)。依專案慣例來選用。如果專案沒有一致的用法,用 「」 比較好。

變數名

一般變數、函式參數

變數(包括函式的參數)以及資料成員的名稱一律小寫,單字之間用底線連接。類別的資料成員結尾處多加一個底線(但結構的資料成員不用),如:a_local_variable、a_ struct_data_member、a_class_data_member_。

1
2
string table_name;  // 可 - 用底線。
string tablename;   // 可 - 全小寫。

類別成員

小寫變數名,最後加底線_

1
2
3
4
5
6
7
class TableInfo {
  ...
  private:
  string table_name_;  // 可 - 字尾加底線。
  string tablename_;   // 可。
  static Pool<TableInfo>* pool_;  // 可。
};

結構成員

不用最後加底線_

1
2
3
4
struct UrlTableProperties {
  string name;
  int num_entries;
}

命名空間

命名空間用小寫字母命名,避免使用不當的縮寫。

把檔案名稱加到名稱中,可以有效建立獨一無二的名稱(例如 在 frobber.h 中,就用 websearch::index::frobber_internal 這樣的名稱)。

函式名

一般函式使用大小寫混合。

一般來說,函式名稱的第一個字母要大寫,其後每個單字的字首字母均大寫。

1
2
3
AddTableEntry()
DeleteUrl()
OpenFileOrDie()

類別、結構、型別別名、列舉,以及模板型別參數

字首大寫,不能有底線,採駝峰式命名

型別名稱的每個單字首字母均大寫,不使用底線:MyExcitingClass,MyExcitingEnum。

所有型別命名(類別、結構、型別別名、列舉,以及模板型別參數)均使用相同規則。型別名稱的第一個字母要大寫,其後每個單字的字首字母均大寫,例如:

1
2
3
4
5
6
7
8
9
10
11
12
13
// 類別和結構
class UrlTable { ...
class UrlTableTester { ...
struct UrlTableProperties { ...

// typedefs
typedef hash_map<UrlTableProperties *, string> PropertiesMap;

// using 別名
using PropertiesMap = hash_map<UrlTableProperties *, string>;

// 列舉
enum UrlTableErrors { ...

常數

宣告時加上 constexpr 或 const,且整個程式執行時間內都不會改變的變數,命名時需以 「k」 開頭,後面的字母以混合大小寫的方式書寫。在少數大寫字無法將單字隔開的情況下,可以使用底線當作區隔。舉例來說:

1
2
const int kDaysInAWeek = 7;
const int kAndroid8_0_0 = 24;  // Android 8.0.0

列舉

  • 列舉若是常數,按照常數標準。
  • 列舉若是型別,按照類別標準。

註解

使用 // 或 /* */,只要一致就好。

註解必須清晰易讀且平舖直述。

類別

類別前都要附帶一份註解(除非看到類別名就知道是在做什麼),描述類別的功能和用法,了解如何使用、何時該使用這個類別。

類別運作以及實作方法的註解應該要放在類別成員函式的實作之處

函式

函式前加上用法說明的註解,除非看到函式名就知道是在做什麼,就可以不用寫。

變數名

通常變數名本身足以很好說明變數的用途。某些情況下,還是需要額外的註解說明。

全域變數

所有的全域變數都要註解說明含義、用途,以及為什麼要將它宣告為全域變數

TODO

TODO 註解要使用全大寫的字串 TODO

在那些臨時的、短期的解決方案,或已經夠好但仍不完美的程式碼旁加上 TODO 註解

1
2
3
// TODO(kl@gmail.com): Use a "*" here for concatenation operator.
// TODO(Zeke) change this to use relations.
// TODO(bug 12345): remove the "Last visitors" feature

棄用deprecation

若已被棄用,用全大寫 DEPRECATED 註解標記。

空白

每一句程式碼內縮2個空白

以下程式碼vector前面留有2個空白

1
2
3
4
int main() {
  vector<int> v = {1, 2, 3, 4, 5};
  return 0;
}

xcode把tab改為2個空白

img

if

注意在所有情況下,if 和左括號間都有個空格。如果有大括號的話,右括號和左大括號之間也要有個空格:

正確方式

1
if (condition) {  // 可 - IF 後面和 { 前面都留有適當的空格。

錯誤方式

1
2
3
if (condition)   // 差 - IF 後面沒空格。
if (condition){   // 差 - { 前面沒空格。
if (condition){  // 前面兩項錯誤犯好犯滿。

if,else if,else

正確方式

1
2
3
4
5
6
7
if (condition) {  // 括號裡沒空格。
  ...  // 2 空格縮排。
} else if (...) {  // else 與 if 的右大括號放在同一行。
  ...
} else {
  ...
}

簡短的條件語句可以寫在同一行,如果這樣可讀性比較高的話。只有當句子簡單並且沒有使用 else 子句時可以使用:

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

如果述句中有 else 的話就禁止如此使用:

1
2
3
// 不可以這樣子 - 當 ELSE 子句存在時,IF 陳述句卻只擠在同一行
if (x) DoThis();
else DoThat();

if大括號

一般來說,單行語句不需要使用大括號,如果你喜歡用也沒問題

1
2
3
4
5
6
if (condition)
  DoSomething();  // 2 空格縮排。

if (condition) {
  DoSomething();  // 2 空格縮排。
}

但如果整個述句中某個 if-else 的區塊使用了大括號的話,其它區塊也必須使用:

1
2
3
4
5
6
7
8
9
10
11
12
// 不可以這樣子 - IF 有大括號 ELSE 卻沒有。
if (condition) {
  foo;
} else
  bar;

// 不可以這樣子 - ELSE 有大括號 IF 卻沒有。
if (condition)
  foo;
else {
  bar;
}

正確方式

1
2
3
4
5
6
// 只要其中一個區塊用了大括號,兩個區塊都要用。
if (condition) {
  foo;
} else {
  bar;
}

for

for () {….}中的內縮仍是2個空白

1
2
3
4
5
6
7
8
int main() {
  vector<int> v = {1, 2, 3, 4, 5};
  for (auto it = v.crbegin(); it != v.crend(); it++) {
  //內縮2個空白
  cout << *it << ", ";
  }
  return 0;
}

for與圓括號()之間要有空白,圓括號()與左大括號{要有空白,並且左大括號{與for在同一行

1
2
  for () {	
  }

圓括號()與裡面的條件,開頭與結尾是沒空白

1
2
  for (int i = 0; i < 10; i++) {	
  }

分號;後留一個空白,=等於的前後留空白,<的前後留空白,++前後不用留空白

1
  for (int i = 0; i < 10; i++)

分號後一定要有空格。

1
2
// 迴圈中,分號後一定要有空格。
  for (auto it = first; ; ) 

引數

大括號{…}裡面的值,逗號(,)右側留一個空白,左側不留空白,大括號{…}中,前後不留空白。

變數名v與類型留一個空白

=等於,前後留空白

1
  vector<int> v = {1, 2, 3, 4, 5};

類別

  • public前面留一個空白
  • public裡面的述敘與public是一個空白
1
2
3
4
5
6
7
8
class callbackObj {
 public://與最邊緣留1個空白
  //與public留1個空白,與最邊緣留2個空白
  void print(const string& msg) {
  //與void留2個空白,與最邊緣留4個空白
  cout << msg << endl;
  }
};

模板

template與尖括號<,中間有空白

1
template <typename T, typename U>

註解空白與對齊

2個斜線後面加一個空白

1
2
// Process "element" unless it was already processed.
auto iter = std::find(v.begin(), v.end(), element);

行尾註解空2個空白

在行尾加兩格空隔後,加上2個斜線,再加一個空白後,開始註解

1
2
if (.....)
  return;  // Error already logged.

註解對齊

1
2
3
4
5
6
7
8
9
10
11
DoSomething();          // 把註解放這裡才能和下一行對齊。
DoSomethingElseThatIsLonger();  // 註解和程式碼之間要有兩個空格。  
{ // 當開啟一個新的作用域時,可以只放一個空隔,
  // 這樣接下來的註解和程式碼都可以和前面那行對齊。
  DoSomethingElse();  // 一般來說行註解前面都需要兩個空隔。
}
std::vector<string> list{
          // 在條列初始化中,用來說明下一個元素的註解...
          "First item",
          // .. 必須要妥善對齊。
          "Second item"};

define

以井號 # 開頭的前置處理器指令一律從一行的最開頭寫起。

1
2
3
4
5
6
7
8
9
10
// 可 - 指令從行首寫起
  if (lopsided_score) {
#if DISASTER_PENDING      // 正確 -- 從行首寫起。
    DropEverything();
# if NOTIFY               // 可以,但非必要 -- # 後面有空格
    NotifyClient();
# endif
#endif
    BackToNormal();
  }

斷行

除非必要,不要使用斷行。尤其是:兩個函式定義之間的斷行不要超過 2 行,函式起始處不要是斷行,最後一行也不要是斷行,其餘地方也儘量少用斷行。在一個程式碼區塊中,斷行像是文章中的段落:在視覺上將兩個想法區隔開來。

  • 函式內開頭或結尾的斷行對可讀性沒有幫助。
  • 在多重 if-else 區塊裡加斷行對可讀性可能有些幫助。
  • 在註解前面加空行通常可以增加可讀性,引入一段新的註解等於在介紹一個新想法的開始,此時加上空行可以清楚地表示這段註解是在說明接下來的程式碼,而非延續前面的行為。

initializer_list

若是你不得不斷行,放在下一行,加上4格的縮排

1
2
3
4
5
6
7
8
9
10
11
12
// 若是你不得不斷行。
SomeFunction(
  {"assume a zero-length name before {"},
  some_other_function_parameter);
SomeType variable{
  "This is too long to fit all in one line"};
MyType m = {  // 你也可以在 { 前斷行。
  superlongvariablename1,
  superlongvariablename2,
  {short, interior, list},
  {interiorwrappinglist,
   interiorwrappinglist2}};

關係運算子放在行尾

若是你不得不斷行,放在下一行,加上4格的縮排

關係運算子斷行時一律放在行尾

1
2
3
4
5
6
7
string time_str =
  to_string(tmnow.tm_year + 1900) + "/" +
  to_string(tmnow.tm_mon + 1) + "/" +
  to_string(tmnow.tm_mday) + "/" +
  to_string(tmnow.tm_hour) + ":" +
  to_string(tmnow.tm_min) + ":" +
  to_string(tmnow.tm_sec);
1
2
3
4
5
if (this_one_thing > this_other_thing &&
  a_third_thing == a_fourth_thing &&
  yet_another & last_one) {
  ...
}

建構子初始值

建構式初值列可以放在同一行,或換行後縮排 4 個空格。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
// 當一行可以塞得下時:
MyClass::MyClass(int var) : some_var_(var) {
  DoSomething();
}

// 如果一行塞不下建構式名稱列和初值列的話,你必須
// 在分號前換行,並且縮排 4 個空格
MyClass::MyClass(int var)
  : some_var_(var), some_other_var_(var + 1) {
  DoSomething();
}

// 若是初值列得分成好幾行的話,每個成員各占一行,
// 排列整齊:
MyClass::MyClass(int var)
  : some_var_(var),       // 4 格縮排
    some_other_var_(var + 1) {  // 對齊前一行
  DoSomething();
}

// 和其他程式碼區塊一樣,如果塞得下的話,右大括號可以
// 和左大括號放在同一行。
MyClass::MyClass(int var)
  : some_var_(var) {}

指標與reference

  • 在存取成員時,句點或箭頭前後沒有空格。
  • 指標運算子 * 或 & 後面沒有空格。
1
2
3
4
x = *p;
p = &x;
x = r.y;
x = r->y;
1
2
3
4
5
6
// 沒問題,空格放在星號前。
char *c;
const string &str;
// 沒問題,空格放在星號後。
char* c;
const string& str;

允許(但不常用)在同一行宣告式中宣告 1 個以上的變數,但其中不得有指標或是 reference 的宣告,因為這樣的宣告式很容易造成混淆。

1
2
// 如果對可讀性有幫助就沒問題。
int x, y;
1
2
3
int x, *y;  // 禁止 - 多個變數的宣告式中不得有 & 或 *
char * c;  // 不好 - 星號前後都有空格
const string & str;  // 不好 - & 前後都有空格

類別

存取控制區塊的宣告依次序是 public:、protected:、private:,每次縮排 1 個空格。

  • 關鍵詞 public:、protected: 和 private: 要縮排 1 個空格。
  • 這些關鍵詞後不要保留空行
  • public 放在最前面,然後是 protected,最後是 private。
  • 繼承關係,:冒號前後有空白,建構子初始,也是冒號前後有空白
1
class MyClass : public OtherClass
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
class MyClass : public OtherClass {
 public:      // 注意有 1 空格縮排!
  MyClass();  // 一般的 2 空格縮排。
  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_;
};

results matching ""

    No results matching ""