Nvim :help
页面,由 生成,从 源文件 使用 tree-sitter-vimdoc 解析器。
#pragma once
开头以防止多次包含。#pragma once
fileio.h
和fileio_defs.h
。这种区分是为了在更改时最小化重新编译。原因是,添加函数或修改函数的签名比更改类型更频繁。目标是实现以下内容extern
变量(包括EXTERN
宏)#define
FUNC_ATTR_ALWAYS_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
来忽略。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
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.
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)
会适当地更新。对于与任何特定变量无关的代码,例如管理外部或内部数据格式的代码(其中合适的 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;
}
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
文档字符串标记来标记已弃用的接口点。@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
case(如果是枚举值,如果未处理任何值,编译器会向您发出警告)。如果 default
case 不应该执行,只需使用 abort()
switch (var) {
case 0:
...
break;
case 1:
...
break;
default:
abort();
}
以枚举值为条件的 Switch 语句,如果它是详尽无遗的,则不应该有 default
case。明确的 case 标签优先于 default
,即使它会导致同一代码有多个 case 标签。例如,而不是case A:
...
case B:
...
case C:
...
default:
...
您应该使用case A:
...
case B:
...
case C:
...
case D:
case E:
case F:
...
某些编译器不识别详尽的枚举 switch 语句为详尽无遗,这会导致在 switch 语句的每个 case 中都有 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
表达式括起来。return expr
中使用括号;仅在您会在 inx = 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 },
};