Nvim :help
頁面,由 產生,源自 原始碼,使用 tree-sitter-vimdoc 解析器。
#pragma once
開頭,以防止多次包含。#pragma once
fileio.h
和 fileio_defs.h
。進行這種區分是為了盡量減少變更時的重新編譯。原因是添加函數或修改函數簽名的頻率高於變更類型。目標是達成以下目的extern
變數(包括 EXTERN
巨集)#define
FUNC_ATTR_ALWAYS_INLINE
屬性的 static inline 函數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.
clint.py
偵測風格錯誤。src/clint.py
是一個 Python 腳本,可讀取原始碼檔案並識別風格錯誤。它並不完美,並且有假陽性和假陰性,但它仍然是一個有價值的工具。可以透過在行尾放置 // NOLINT
來忽略假陽性。clint.py
未涵蓋的情況,src/uncrustify.cfg
是預期程式碼格式的權威。如果 uncrustify
規則涵蓋了 clint.py
中的檢查,我們會將它們移除。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
。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) {
}
char
、int
、uint8_t
、int8_t
、uint16_t
、int16_t
、uint32_t
、int32_t
、uint64_t
、int64_t
、uintmax_t
、intmax_t
、size_t
、ssize_t
、uintptr_t
、intptr_t
和 ptrdiff_t
。int
用於錯誤程式碼和區域、簡單的變數。char
的有符號性是實作定義的。uint8_t
等)。printf
格式預留位置。如果您必須格式化固定寬度整數,請轉換為 uintmax_t
或 intmax_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())) {
static void f(void);
static void f(void)
{
...
}
<HEADER>
<PUBLIC FUNCTION DEFINITIONS>
<STATIC FUNCTION DEFINITIONS>
.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
sizeof(void *)
!= sizeof(int)
。如果您想要指標大小的整數,請使用 intptr_t
。int64_t
/`uint64_t` 成員的類別/結構在 64 位元系統上預設將以 8 位元組對齊。如果您有在 32 位元和 64 位元程式碼之間在磁碟上共用這些結構,則需要確保它們在兩種架構上都以相同的方式封裝。大多數編譯器都提供了一種變更結構對齊的方式。對於 gcc,您可以使用 __attribute__((packed))
。MSVC 提供 #pragma pack()
和 __declspec(align())
。LL
或 ULL
後綴來建立 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;
}
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
。MyExcitingStruct
。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
//
風格的語法。// This is a comment spanning
// multiple lines
f();
.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;
// 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.
}
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);
// 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([email protected]): Use a "*" here for concatenation operator.
// TODO(Zeke): change this to use relations.
如果您的 TODO
採用「在未來某個日期執行某事」的形式,請確保您要包含非常具體的日期(「在 2005 年 11 月之前修復」)或非常具體的事件(「當所有客戶端都能處理 XML 回應時,移除此程式碼」)。@deprecated
docstring 標記來標記已棄用的介面點。@deprecated
的註解來將介面標記為已棄用。該註解會放在介面宣告之前或與宣告位於同一行。@deprecated
之後,請在括號中寫下您的姓名、電子郵件或其他識別符。DEPRECATED
並不會神奇地導致任何呼叫位置發生變更。如果您希望人們真正停止使用已棄用的工具,您必須自己修復這些呼叫位置,或招募一組人員來協助您。"\uFEFF"
是 Unicode 零寬度不換行空格字元,如果以直接 UTF-8 的形式包含在原始碼中,則會不可見。{
後面和 }
前面加上一個空格{}
是具有該名稱的函式呼叫的括號一樣。如果沒有名稱,請假設名稱長度為零。struct my_struct m = { // Here, you could also break before {.
superlongvariablename1,
superlongvariablename2,
{ short, interior, list },
{ interiorwrappinglist,
interiorwrappinglist2 } };
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 },
};