Dev_style

Nvim の :help ページは、生成されたもので、ソースtree-sitter-vimdocパーサーを使って生成しています。


Nvim スタイルガイド
Nvim のソースコードを扱う開発者向けのスタイルガイドライン。

背景

コードベースを管理しやすい状態に保つ方法の一つは、一貫性を強制することです。プログラマーは他の人のコードを見て、それをすぐに理解できることが非常に重要です。
統一されたスタイルを維持し、規約に従うことは、様々なシンボルが何であるか、それらについてどのような不変条件が当てはまるかを推論するために、「パターンマッチング」をより簡単に行えることを意味します。共通の、必須のイディオムとパターンを作成することで、コードをより理解しやすくします。
場合によっては、特定のスタイルルールを変更する正当な議論があるかもしれませんが、一貫性を保つために現状を維持しています。

ヘッダーファイル dev-style-header

ヘッダーガード
すべてのヘッダーファイルは、多重インクルードを防ぐために#pragma onceで始める必要があります。
foo/bar.hの場合
#pragma once
ヘッダーシステム
Nvim は2種類のヘッダーを使用します。通常のヘッダーと "defs" ヘッダーです。通常、各通常のヘッダーには、対応する defs ヘッダーがあります。例えば、fileio.hfileio_defs.h です。この区別は、変更時の再コンパイルを最小限に抑えるために行われます。これは、関数の追加や関数のシグネチャの変更が型の変更よりも頻繁に発生するためです。目標は以下を達成することです。
すべてのヘッダー(defs と通常)は、defs ヘッダー、システムヘッダー、および生成された宣言のみを含める必要があります。言い換えれば、ヘッダーは通常のヘッダーを含めてはなりません。
ソース(.c)ファイルはすべてのヘッダーを含めることができますが、シンボルが必要な場合、型ではなく通常のヘッダーのみを含める必要があります。
どこに何を置くかを決定するには、次のガイドラインを使用してください。
シンボル
通常の関数宣言
extern 変数 (EXTERN マクロを含む)
非シンボル
マクロ、つまり #define
FUNC_ATTR_ALWAYS_INLINE 属性を持つ static inline 関数
typedef
struct
enum
すべてのシンボルは、通常のヘッダーに移動する必要があります。
複数のヘッダーで使用される非シンボルは、defs ヘッダーに移動する必要があります。これは、ヘッダーが defs ヘッダーのみを含めるようにするためです。逆に、単一のヘッダーでのみ使用される非シンボルは、そのヘッダーに移動する必要があります。
例外:マクロが関数を呼び出す場合、通常のヘッダーに移動する必要があります。

スコープ dev-style-scope

ローカル変数
関数の変数を可能な限り狭いスコープに配置し、宣言時に変数を初期化します。
C99 では、関数内の任意の場所で変数を宣言できます。可能な限りローカルなスコープで、最初の使用箇所にできるだけ近い場所で宣言します。これにより、読者が宣言を見つけやすく、変数の型と初期化された値を確認しやすくなります。特に、宣言と代入の代わりに初期化を使用する必要があります。例:
int i;
i = f();      // ❌: initialization separate from declaration.
int j = g();  // ✅: declaration has initialization.
初期化
初期化されていない場合は、1行に複数の宣言を定義できますが、各初期化は別の行で行う必要があります。
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
src/uncrustify.cfg は、clint.py でカバーされていない場合の、期待されるコードフォーマットの権威です。clint.py のチェックが uncrustify ルールでカバーされている場合は、削除します。

その他の 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 を配置する場所
const int *foo の代わりに int const *foo の形式を好む人もいます。これは、const が記述しているオブジェクトの後に常に続くというルールを維持しているため、より読みやすいと主張します。ただし、この一貫性の議論は、ほとんどの const 式が1つの 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_t、および ptrdiff_t のみを使用します。
エラーコードとローカルな些細な変数には int のみを使用します。
整数型を変換するときは注意してください。整数の変換と昇格は、直感的でない動作を引き起こす可能性があります。char の符号付きは実装定義であることに注意してください。
公開型は固定幅(uint8_t など)を持つ必要があります。
固定幅型には便利な printf フォーマットプレースホルダーはありません。固定幅の整数をフォーマットする必要がある場合は、uintmax_t または intmax_t にキャストしてください。
型 符号なし 符号付き char %hhu %hhd int n/a %d (u)intmax_t %ju %jd (s)size_t %zu %zd ptrdiff_t %tu %td
ブール値
ブール値を表すには bool を使用します。
int loaded = 1;  // ❌: loaded should have type bool.
条件
「ヨーダ条件」は使用しないでください。条件ごとに最大1つの代入を使用してください。
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 が含まれている必要があります。
インクルードは、.c ファイルでは他の #includes と 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()) を提供しています。
64ビット定数を作成するには、必要に応じて LL または ULL サフィックスを使用します。例:
int64_t my_value = 0x123456789LL;
uint64_t my_mask = 3ULL << 48;
sizeof ~
sizeof(type) よりも sizeof(varname) を優先します。
特定の変数のサイズを取得する場合は、sizeof(varname) を使用します。sizeof(varname) は、誰かが変数型を現在または後で変更した場合に適切に更新されます。外部または内部データ形式を管理するコードなど、適切な C 型の変数が便利ではない特定の変数に関係のないコードには、sizeof(type) を使用できます。
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 など)は使用しないでください。
一般的に、ファイル名は非常に具体的にしてください。たとえば、logs.h ではなく http_server_logs.h を使用します。
型名
Typedef で定義された struct と enum は大文字で始まり、各新しい単語に大文字があり、アンダースコアはありません。MyExcitingStruct
Typedef で定義されていない struct と enum は、すべて小文字で、単語間にアンダースコアがあります。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を読んでいる人にとって役立つと感じた場合は、代わりにそこに配置しても構いませんが、ドキュメントが.hファイルにあることを.cで言及してください。
.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;
  ...
};
フィールドコメントが短い場合は、フィールドの横に配置することもできます。ただし、1つの構造体内で一貫性を保ち、必要な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だけでなくより多くの文字を処理できるほとんどのツールで理解されるエンコーディングであるためです。
16進数エンコーディングもOKであり、可読性を高める場合は推奨されます。たとえば、"\uFEFF"はUnicodeのゼロ幅ノーブレークスペース文字であり、UTF-8として直接ソースに含めると非表示になります。
中括弧で囲まれた初期化子リスト
中括弧で囲まれたリストは、その場所に配置する関数呼び出しをフォーマットするのとまったく同じようにフォーマットしますが、{の後に1つのスペース、}の前に1つのスペースを配置します。
中括弧で囲まれたリストが名前(型名や変数名など)に続く場合は、{}がその名前の関数呼び出しの括弧であるかのようにフォーマットします。名前がない場合は、長さがゼロの名前を想定します。
struct my_struct m = {  // Here, you could also break before {.
    superlongvariablename1,
    superlongvariablename2,
    { short, interior, list },
    { interiorwrappinglist,
      interiorwrappinglist2 } };
ループとswitchステートメント
ケース間の自明ではないフォールスルーを注釈します。
列挙値で条件付けられていない場合、switchステートメントには常にdefaultケースが必要です(列挙値の場合、値が処理されない場合はコンパイラによって警告されます)。デフォルトケースが実行されるべきではない場合は、abort()を使用するだけです。
switch (var) {
  case 0:
    ...
    break;
  case 1:
    ...
    break;
  default:
    abort();
}
列挙値で条件付けられているswitchステートメントは、網羅的である場合はdefaultケースを持つべきではありません。明示的なケースラベルは、同じコードに対して複数のケースラベルにつながる場合でも、defaultよりも優先されます。たとえば、代わりに
case A:
  ...
case B:
  ...
case C:
  ...
default:
  ...
次を使用する必要があります
case A:
  ...
case B:
  ...
case C:
  ...
case D:
case E:
case F:
  ...
一部のコンパイラは、網羅的な列挙型switchステートメントを網羅的として認識しないため、switchステートメントのすべてのケースにreturnステートメントがあるが、包括的な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式を不必要に括弧で囲まないでください。
return exprで括弧を使用するのは、`x = 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  },
};

終わりに

このスタイルガイドは、コードをより読みやすくすることを目的としています。もし明確さのためにルールを破る必要があると思う場合は、そうしてください!ただし、その理由を説明するメモをプルリクエストに追加してください。
メイン
コマンド索引
クイックリファレンス