Dev_style

Nvim :help 頁面,由 產生,源自 原始碼,使用 tree-sitter-vimdoc 解析器。


Nvim 風格指南
適用於開發 Nvim 原始碼的開發人員的風格指南。

背景

我們保持程式碼庫可管理的一種方式是強制執行一致性。任何程式設計師都能夠查看別人的程式碼並快速理解它,這一點非常重要。
維持統一的風格並遵循慣例,意味著我們可以更輕鬆地使用「模式匹配」來推斷各種符號是什麼,以及它們的哪些不變性是正確的。創建常見的、必需的慣用語和模式,可以使程式碼更容易理解。
在某些情況下,可能有充分的理由更改某些風格規則,但我們仍然保持原樣,以維持一致性。

標頭檔 dev-style-header

標頭保護
所有標頭檔都應以 #pragma once 開頭,以防止多次包含。
在 foo/bar.h 中
#pragma once
標頭系統
Nvim 使用兩種標頭。有「一般」標頭和「defs」標頭。通常,每個一般標頭都有一個對應的 defs 標頭,例如 fileio.hfileio_defs.h。進行這種區分是為了盡量減少變更時的重新編譯。原因是添加函數或修改函數簽名的頻率高於變更類型。目標是達成以下目的
所有標頭(defs 和一般)都必須只包含 defs 標頭、系統標頭和產生的宣告。換句話說,標頭不得包含一般標頭。
原始碼 (.c) 檔案可以包含所有標頭,但如果它們需要符號而不是類型,則只應包含一般標頭。
使用以下指南來決定要將什麼放在哪裡
符號
常規函數宣告
extern 變數(包括 EXTERN 巨集)
非符號
巨集,即 #define
具有 FUNC_ATTR_ALWAYS_INLINE 屬性的 static inline 函數
typedefs
結構體
枚舉
所有符號都必須移到一般標頭中。
多個標頭使用的非符號應移到 defs 標頭中。這是為了確保標頭只包含 defs 標頭。相反地,只有單個標頭使用的非符號應移到該標頭中。
例外:如果巨集呼叫函數,則必須將其移到一般標頭中。
區域變數
將函數的變數放置在盡可能小的範圍內,並在宣告中初始化變數。
C99 允許您在函數中的任何位置宣告變數。將它們宣告在盡可能小的範圍內,並盡可能接近第一次使用的地方。這使讀者更容易找到宣告,並查看變數的類型以及它初始化為的值。特別是,應使用初始化而不是宣告和賦值,例如
int i;
i = f();      // ❌: initialization separate from declaration.
int j = g();  // ✅: declaration has initialization.
初始化
如果未初始化,則可以在一行中定義多個宣告,但每個初始化都應在單獨的一行中完成。
int i;
int j;              // ✅
int i, j;           // ✅: multiple declarations, no initialization.
int i = 0;
int j = 0;          // ✅: one initialization per line.
int i = 0, j;       // ❌: multiple declarations with initialization.
int i = 0, j = 0;   // ❌: multiple declarations with initialization.

Nvim 特有的魔術

clint
使用 clint.py 偵測風格錯誤。
src/clint.py 是一個 Python 腳本,可讀取原始碼檔案並識別風格錯誤。它並不完美,並且有假陽性和假陰性,但它仍然是一個有價值的工具。可以透過在行尾放置 // NOLINT 來忽略假陽性。
uncrustify
對於 clint.py 未涵蓋的情況,src/uncrustify.cfg 是預期程式碼格式的權威。如果 uncrustify 規則涵蓋了 clint.py 中的檢查,我們會將它們移除。

其他 C 功能 dev-style-features

可變長度陣列和 alloca()
我們不允許可變長度陣列或 alloca()
可變長度陣列可能會導致難以偵測的堆疊溢位。
後置遞增和後置遞減
在語句中使用後綴形式 (i++)。
for (int i = 0; i < 3; i++) { }
int j = ++i;  // ✅: ++i is used as an expression.
for (int i = 0; i < 3; ++i) { }
++i;  // ❌: ++i is used as a statement.
const 的使用
盡可能使用 const 指標。避免在非指標參數定義上使用 const
const 放在哪裡
有些人偏愛 int const *foo 而不是 const int *foo 的形式。他們認為這樣更具可讀性,因為它更一致:它保留了 const 始終跟隨它所描述的物件的規則。但是,這種一致性論點不適用於具有少量深度巢狀指標表達式的程式碼庫,因為大多數 const 表達式只有一個 const,並且它適用於底層值。在這種情況下,沒有一致性需要維護。將 const 放在第一位可以說更具可讀性,因為它遵循英文,將「形容詞」(const) 放在「名詞」(int) 之前。
也就是說,雖然我們鼓勵將 const 放在第一位,但我們並不要求這樣做。但請與您周圍的程式碼保持一致!
void foo(const char *p, int i);
}
int foo(const int a, const bool b) {
}
int foo(int *const p) {
}
整數類型
在內建整數類型中,只使用 charintuint8_tint8_tuint16_tint16_tuint32_tint32_tuint64_tint64_tuintmax_tintmax_tsize_tssize_tuintptr_tintptr_tptrdiff_t
僅將 int 用於錯誤程式碼和區域、簡單的變數。
轉換整數類型時請小心。整數轉換和提升可能會導致非直觀的行為。請注意,char 的有符號性是實作定義的。
公用類型必須具有固定寬度 (uint8_t 等)。
固定寬度類型沒有方便的 printf 格式預留位置。如果您必須格式化固定寬度整數,請轉換為 uintmax_tintmax_t
類型 有符號 無符號 char %hhu %hhd int 不適用 %d (u)intmax_t %ju %jd (s)size_t %zu %zd ptrdiff_t %tu %td
布林值
使用 bool 表示布林值。
int loaded = 1;  // ❌: loaded should have type bool.
條件
不要使用「尤達條件」。每個條件最多使用一個賦值。
if (1 == x) {
if (x == 1) {  //use this order
if ((x = f()) && (y = g())) {
函數宣告
每個函數都不得有單獨的宣告。
函數宣告由 gen_declarations.lua 腳本建立。
static void f(void);
static void f(void)
{
  ...
}
一般轉換單元版面配置
公用函數的定義在靜態函數的定義之前。
<HEADER>
<PUBLIC FUNCTION DEFINITIONS>
<STATIC FUNCTION DEFINITIONS>
與宣告產生器的整合
每個 C 檔案都必須包含由 #ifdef INCLUDE_GENERATED_DECLARATIONS 保護的產生標頭檔的 #include。
Include 必須放在 .c 檔案中的其他 #include 和 typedef 之後,以及標頭檔中的所有其他內容之後。如果 .c 檔案不包含任何靜態函數,則允許在 .c 檔案中省略 #include。
包含的檔案名稱由不帶副檔名的 .c 檔案名稱組成,前面是相對於 src/nvim 的目錄名稱。包含靜態函數宣告的檔案名稱以 .c.generated.h 結尾,*.h.generated.h 檔案僅包含非靜態函數宣告。
// src/nvim/foo.c file
#include <stddef.h>
typedef int FooType;
#ifdef INCLUDE_GENERATED_DECLARATIONS
# include "foo.c.generated.h"
#endif
…
// src/nvim/foo.h file
#pragma once
…
#ifdef INCLUDE_GENERATED_DECLARATIONS
# include "foo.h.generated.h"
#endif
64 位元可攜性
程式碼應與 64 位元和 32 位元相容。請記住列印、比較和結構對齊的問題。
請記住 sizeof(void *) != sizeof(int)。如果您想要指標大小的整數,請使用 intptr_t
您可能需要注意結構對齊,特別是對於儲存在磁碟上的結構。任何具有 int64_t/`uint64_t` 成員的類別/結構在 64 位元系統上預設將以 8 位元組對齊。如果您有在 32 位元和 64 位元程式碼之間在磁碟上共用這些結構,則需要確保它們在兩種架構上都以相同的方式封裝。大多數編譯器都提供了一種變更結構對齊的方式。對於 gcc,您可以使用 __attribute__((packed))。MSVC 提供 #pragma pack()__declspec(align())
根據需要使用 LLULL 後綴來建立 64 位元常數。例如
int64_t my_value = 0x123456789LL;
uint64_t my_mask = 3ULL << 48;
sizeof ~
偏好 sizeof(varname) 而不是 sizeof(type)
當您取得特定變數的大小時,請使用 sizeof(varname)。如果有人現在或稍後變更變數類型,sizeof(varname) 將會適當地更新。您可以將 sizeof(type) 用於與任何特定變數無關的程式碼,例如管理外部或內部資料格式的程式碼,其中適當的 C 類型的變數不方便。
Struct data;
memset(&data, 0, sizeof(data));
memset(&data, 0, sizeof(Struct));
if (raw_size < sizeof(int)) {
  fprintf(stderr, "compressed record not big enough for count: %ju", raw_size);
  return false;
}

命名 dev-style-naming

最重要的規則是一致性規則,它們控制命名。名稱的樣式會立即告知我們所命名實體是什麼類型:類型、變數、函數、常數、巨集等等,而無需我們搜尋該實體的宣告。我們大腦中的模式匹配引擎在很大程度上依賴於這些命名規則。
命名規則相當隨意,但我們認為一致性比這個領域的個人偏好更重要,因此無論您是否認為它們合理,規則就是規則。
一般命名規則
函數名稱、變數名稱和檔案名稱應具描述性;避免縮寫。
在合理的範圍內,給予盡可能具描述性的名稱。不要擔心節省水平空間,因為讓新的讀者能夠立即理解您的程式碼遠比這更重要。不要使用對專案外的讀者來說含糊不清或不熟悉的縮寫,並且不要透過刪除單字中的字母來縮寫。
int price_count_reader;    // No abbreviation.
int num_errors;            // "num" is a widespread convention.
int num_dns_connections;   // Most people know what "DNS" stands for.
int n;                     // Meaningless.
int nerr;                  // Ambiguous abbreviation.
int n_comp_conns;          // Ambiguous abbreviation.
int wgc_connections;       // Only your group knows what this stands for.
int pc_reader;             // Lots of things can be abbreviated "pc".
int cstmr_id;              // Deletes internal letters.
檔案名稱
檔案名稱應全部小寫,並且可以包含底線 (_)。
使用底線分隔單字。可接受的檔案名稱範例
my_useful_file.c
getline_fix.c  // ✅: getline refers to the glibc function.
C 檔案應以 .c 結尾,標頭檔應以 .h 結尾。
不要使用 /usr/include 中已存在的檔案名稱,例如 db.h
一般來說,請讓您的檔案名稱非常明確。例如,使用 http_server_logs.h 而不是 logs.h
類型名稱
Typedef-ed 結構體和枚舉以大寫字母開頭,每個新單字都有一個大寫字母,沒有底線:MyExcitingStruct
Non-Typedef-ed 結構體和枚舉全部小寫,單字之間使用底線:struct my_exciting_struct
struct my_struct {
  ...
};
typedef struct my_struct MyAwesomeStruct;
變數名稱
變數名稱全部小寫,單字之間使用底線。例如:my_exciting_local_variable
常見變數名稱
例如
string table_name;  // ✅: uses underscore.
string tablename;   // ✅: all lowercase.
string tableName;   // ❌: mixed case.
結構體變數
結構體中的資料成員應像常規變數一樣命名。
struct url_table_properties {
  string name;
  int num_entries;
}
全域變數
除非絕對必要,否則不要使用全域變數。全域變數的前綴應為 g_
常數名稱
使用 k 後面接混合大小寫:kDaysInAWeek
所有編譯時間常數,無論它們是在本機還是全域宣告,都遵循與其他變數略有不同的命名慣例。使用 k 後面接第一個字母大寫的單字
const int kDaysInAWeek = 7;
函數名稱
函數名稱全部小寫,單字之間使用底線。例如:my_exceptional_function()。同一標頭檔中的所有函數應具有共同的前綴。
os_unix.h
void unix_open(const char *path);
void unix_user_id(void);
如果您的函數在發生錯誤時崩潰,則應在函數名稱附加 or_die。這僅適用於生產程式碼可能使用的函數,以及在正常操作期間合理可能發生的錯誤。
枚舉器名稱
枚舉器應像常數一樣命名:kEnumName
enum url_table_errors {
  kOK = 0,
  kErrorOutOfMemory,
  kErrorMalformedInput,
};
巨集名稱
它們看起來像這樣:MY_MACRO_THAT_SCARES_CPP_DEVELOPERS
#define ROUND(x) ...
#define PI_ROUNDED 5.0

註解 dev-style-comments

註解對於保持我們的程式碼可讀性至關重要。以下規則描述您應註解什麼以及在哪裡註解。但請記住:雖然註解非常重要,但最好的程式碼是自我描述的。
撰寫註解時,請為您的受眾著想:也就是下一個需要理解您程式碼的貢獻者。請慷慨大方 — 因為下一個可能就是您自己!
Nvim 使用 Doxygen 註解。
註解風格
僅使用 // 風格的語法。
// This is a comment spanning
// multiple lines
f();
檔案註解
每個檔案都以描述其內容的註解開始。
法律聲明
我們沒有這種東西。這些都在 LICENSE 中,而且只在那裡。
檔案內容
每個檔案的頂部都應有一個註解,描述其內容。
一般來說,.h 檔案會描述在該檔案中宣告的變數和函式,並概述它們的用途和使用方式。.c 檔案應包含更多關於實作細節的資訊,或對複雜演算法的討論。如果您認為實作細節或演算法的討論對閱讀 .h 的人來說很有用,請隨意將其放在那裡,但請在 .c 中提及文件在 .h 檔案中。
請勿在 .h.c 中重複註解。重複的註解會產生歧異。
/// A brief description of this file.
///
/// A longer description of this file.
/// Be very generous here.
結構體註解
每個結構體定義都應附有描述其用途和使用方式的註解。
/// Window info stored with a buffer.
///
/// Two types of info are kept for a buffer which are associated with a
/// specific window:
/// 1. Each window can have a different line number associated with a
/// buffer.
/// 2. The window-local options for a buffer work in a similar way.
/// The window-info is kept in a list at g_wininfo.  It is kept in
/// most-recently-used order.
struct win_info {
  /// Next entry or NULL for last entry.
  WinInfo *wi_next;
  /// Previous entry or NULL for first entry.
  WinInfo *wi_prev;
  /// Pointer to window that did the wi_fpos.
  Win *wi_win;
  ...
};
如果欄位註解很短,您也可以將它們放在欄位旁邊。但請在一個結構體內保持一致,並遵循必要的 doxygen 風格。
struct wininfo_S {
  WinInfo *wi_next;  ///< Next entry or NULL for last entry.
  WinInfo *wi_prev;  ///< Previous entry or NULL for first entry.
  Win *wi_win;       ///< Pointer to window that did the wi_fpos.
  ...
};
如果您已在檔案頂部的註解中詳細描述了結構體,請隨意簡單地說明「請參閱檔案頂部的註解以獲取完整說明」,但請務必加上某種類型的註解。
記錄結構體所做的同步假設(如果有的話)。如果多個執行緒可以存取結構體的實例,請格外小心記錄圍繞多執行緒使用的規則和不變量。
函式註解
宣告註解描述函式的使用方式;函式定義的註解描述其操作方式。
函式宣告
每個函式宣告之前都應立即加上註解,描述該函式的作用以及如何使用它。這些註解應該是描述性的(「開啟檔案」)而不是命令式的(「開啟檔案」);註解描述函式,而不是告訴函式該做什麼。一般來說,這些註解不會描述函式如何執行其任務。相反地,這應該留給函式定義中的註解。
在函式宣告的註解中提及的事項類型
如果函式配置了呼叫者必須釋放的記憶體。
任何參數是否可以為空指標。
如果函式的使用方式對效能有任何影響。
函式是否為可重入的。它的同步假設是什麼?
/// Brief description of the function.
///
/// Detailed description.
/// May span multiple paragraphs.
///
/// @param arg1 Description of arg1
/// @param arg2 Description of arg2. May span
///        multiple lines.
///
/// @return Description of the return value.
Iterator *get_iterator(void *arg1, void *arg2);
函式定義
如果函式如何執行其工作有任何複雜之處,則函式定義應有一個解釋性註解。例如,在定義註解中,您可能會描述您使用的任何程式碼技巧、概述您執行的步驟,或解釋為什麼您選擇以這種方式實作函式而不是使用可行的替代方案。例如,您可能會提及為什麼必須在函式的前半部分獲取鎖,但在後半部分則不需要。
請注意,您不應該只是重複在函式宣告中給出的註解,無論是在 .h 檔案中還是其他地方。簡要回顧函式的作用是可以的,但註解的重點應該放在它是如何執行的。
// Note that we don't use Doxygen comments here.
Iterator *get_iterator(void *arg1, void *arg2)
{
  ...
}
變數註解
一般來說,變數的實際名稱應該具有足夠的描述性,可以很好地了解變數的用途。在某些情況下,需要更多註解。
全域變數
所有全域變數都應有一個註解,描述它們是什麼以及它們的用途。例如
/// The total number of tests cases that we run
/// through in this regression test.
const int kNumTestCases = 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.
}
請注意,既有描述程式碼正在做什麼的註解,也有提及當函式傳回時已記錄錯誤的註解。
如果您在後續幾行中有幾個註解,通常將它們對齊會更具可讀性
do_something();                      // Comment here so the comments line up.
do_something_else_that_is_longer();  // 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.
  do_something_else();  // Two spaces before line comments normally.
}
NULL、true/false、1、2、3...
當您將空指標、布林值或文字整數值傳遞給函式時,您應該考慮添加一個關於它們是什麼的註解,或透過使用常數使您的程式碼自我說明。例如,比較
bool success = calculate_something(interesting_value,
                                   10,
                                   false,
                                   NULL);  // What are these arguments??
bool success = calculate_something(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 = calculate_something(interesting_value,
                                   kDefaultBaseValue,
                                   kFirstTimeCalling,
                                   null_callback);
不該做的事
請注意,您絕不應描述程式碼本身。假設閱讀程式碼的人比您更了解 C,即使他或她不知道您嘗試做什麼
// Now go through the b array and make sure that if i occurs,
// the next element is i+1.
...        // Geez.  What a useless comment.
標點符號、拼寫和語法
請注意標點符號、拼寫和語法;閱讀寫得好的註解比閱讀寫得不好的註解更容易。
註解應像敘事文本一樣可讀,具有適當的大小寫和標點符號。在許多情況下,完整的句子比不完整的句子更具可讀性。較短的註解,例如程式碼行末尾的註解,有時可以不太正式,但您應該與您的風格保持一致。
雖然程式碼審查人員指出您在應該使用分號時使用了逗號可能會令人沮喪,但原始碼保持高度清晰和可讀性非常重要。正確的標點符號、拼寫和語法有助於實現這一目標。
TODO 註解
對於暫時的程式碼、短期解決方案或足夠好但不完美的程式碼,請使用 TODO 註解。
TODO 應包含全部大寫的字串 TODO,後跟最能提供有關 TODO 所引用問題上下文的人員的姓名、電子郵件地址或其他識別符。主要目的是擁有一個一致的 TODO 格式,可以搜尋以找到可以根據要求提供更多詳細資訊的人員。TODO 並不是保證所引用的人員會修復該問題的承諾。因此,當您建立 TODO 時,幾乎總是會提供您的姓名。
// TODO([email protected]): Use a "*" here for concatenation operator.
// TODO(Zeke): change this to use relations.
如果您的 TODO 採用「在未來某個日期執行某事」的形式,請確保您要包含非常具體的日期(「在 2005 年 11 月之前修復」)或非常具體的事件(「當所有客戶端都能處理 XML 回應時,移除此程式碼」)。
棄用註解
使用 @deprecated docstring 標記來標記已棄用的介面點。
您可以透過撰寫包含全部大寫單字 @deprecated 的註解來將介面標記為已棄用。該註解會放在介面宣告之前或與宣告位於同一行。
@deprecated 之後,請在括號中寫下您的姓名、電子郵件或其他識別符。
棄用註解必須包含簡單、清楚的指示,供人們修復其呼叫位置。在 C 中,您可以將已棄用的函式實作為呼叫新介面點的內聯函式。
將介面點標記為 DEPRECATED 並不會神奇地導致任何呼叫位置發生變更。如果您希望人們真正停止使用已棄用的工具,您必須自己修復這些呼叫位置,或招募一組人員來協助您。
新的程式碼不應包含對已棄用介面點的呼叫。請改用新的介面點。如果您無法理解指示,請找到建立棄用的人員,並請他們協助您使用新的介面點。

格式化 dev-style-format

程式碼風格和格式化相當隨意,但如果每個人都使用相同的風格,則專案會更容易追蹤。個人可能不同意格式化規則的每個方面,並且有些規則可能需要一些時間來適應,但所有專案貢獻者都必須遵循風格規則,以便他們可以輕鬆地閱讀和理解每個人的程式碼,這點非常重要。
非 ASCII 字元
非 ASCII 字元應該很少使用,並且必須使用 UTF-8 格式。
您不應該在原始碼中硬式編碼面向使用者的文字(還是應該?),即使是英文也是如此,因此應該很少使用非 ASCII 字元。但是,在某些情況下,將這些單字包含在程式碼中是適當的。例如,如果您的程式碼解析來自國外來源的資料檔案,則硬式編碼那些資料檔案中用作分隔符的非 ASCII 字串可能是適當的。更常見的是,單元測試程式碼(不需要本地化)可能包含非 ASCII 字串。在這種情況下,您應該使用 UTF-8,因為這是一種大多數能夠處理不僅僅是 ASCII 的工具可以理解的編碼。
十六進位編碼也是可以的,並且在提高可讀性的情況下鼓勵使用 — 例如,"\uFEFF" 是 Unicode 零寬度不換行空格字元,如果以直接 UTF-8 的形式包含在原始碼中,則會不可見。
大括號初始化列表
將大括號列表格式化為您將在其位置格式化函式呼叫的方式,但在 { 後面和 } 前面加上一個空格
如果大括號列表後跟一個名稱(例如,類型或變數名稱),請格式化,就好像 {} 是具有該名稱的函式呼叫的括號一樣。如果沒有名稱,請假設名稱長度為零。
struct my_struct m = {  // Here, you could also break before {.
    superlongvariablename1,
    superlongvariablename2,
    { short, interior, list },
    { interiorwrappinglist,
      interiorwrappinglist2 } };
迴圈和 Switch 陳述式
註解案例之間重要的 fall-through。
如果不是條件式列舉值,則 switch 陳述式應始終具有 default 案例(如果是列舉值,如果沒有處理任何值,編譯器會警告您)。如果 default 案例永遠不應執行,請直接使用 abort()
switch (var) {
  case 0:
    ...
    break;
  case 1:
    ...
    break;
  default:
    abort();
}
如果列舉值是窮舉的,則以列舉值為條件的 Switch 陳述式不應具有 default 案例。即使會導致同一程式碼有多個 case 標籤,也應優先選擇明確的 case 標籤,而非 default。例如,不要使用
case A:
  ...
case B:
  ...
case C:
  ...
default:
  ...
您應該使用
case A:
  ...
case B:
  ...
case C:
  ...
case D:
case E:
case F:
  ...
某些編譯器不將窮舉列舉 switch 陳述式識別為窮舉,這會在 switch 陳述式的每個案例中都有 return 陳述式,但沒有 catch-all return 陳述式時導致編譯器警告。為了修復這些虛假的錯誤,建議您在 switch 陳述式之後使用 UNREACHABLE,以明確告知編譯器 switch 陳述式始終會傳回,並且之後的任何程式碼都無法存取。例如
enum { A, B, C } var;
...
switch (var) {
  case A:
    return 1;
  case B:
    return 2;
  case C:
    return 3;
}
UNREACHABLE;
傳回值
不要不必要地用括號括住 return 運算式。
僅在 x = expr; 中使用括號的位置使用 return expr 中的括號。
return result;
return (some_long_condition && another_condition);
return (value);  // You wouldn't write var = (value);
return(result);  // return is not a function!
水平空白
水平空白的使用取決於其位置。
變數
int long_variable = 0;  // Don't align assignments.
int i             = 1;
struct my_struct {  // Exception: struct arrays.
  const char *boy;
  const char *girl;
  int pos;
} my_variable[] = {
  { "Mia",       "Michael", 8  },
  { "Elizabeth", "Aiden",   10 },
  { "Emma",      "Mason",   2  },
};

結語

本風格指南旨在使程式碼更易讀。如果您認為為了清晰起見必須違反其規則,請務必這麼做!但請在您的 Pull Request 中添加註解,說明您的理由。
主程式
指令索引
快速參考