代码风格统一有助于团队协作与代码review,业界用的比较多的是google的风格,本节来点不一样的,看看咱们平时用的比较多的工具curl团队的代码规范是什么样子的。
curl简单说一下,它在命令行或脚本中传输数据非常有用,大家也肯定用过,其源码实现可以在github上查看
https://github.com/curl/curl
下面我们来从几个方面看看curl的C语言开发规范。
新的函数和变量名称应该是逻辑的、可理解的,并且根据它们的用途进行命名。
文件局部函数应该被声明为静态的,建议是小写字母名称。
只使用空格进行缩进,不使用制表符。每个新的开放大括号使用两个空格。
if(something_is_true) {
while(second_statement == fine) {
moo();
}
}
由于编写的是 C89 代码,不允许使用 // 注释。它们直到 C99 标准才被引入。只使用 **/* 注释 */**。
/* 这是一个注释 */
curl 中的源代码永远不应该超过 79 列,即使在现代大屏幕和高分辨率屏幕时代,仍然有两个原因要保持这一点:
在 if/while/do/for 表达式中,我们将开放大括号写在与关键字同一行,然后将闭合大括号设置在与初始关键字相同缩进级别的同一行。就像这样:
if(age < 40) {
/* 显然是年轻人 */
}
如果它们只包含一个一行语句,则可以省略大括号:
if(!x)
continue;
对于函数,开放大括号应该写在单独的一行上:
int main(int argc, char **argv)
{
return 1;
}
在使用大括号添加 else 子句到条件表达式时,我们将其添加到关闭大括号后的新行。就像这样:
if(age < 40) {
/* 显然是年轻人 */
}
else {
/* 可能是脾气暴躁的 */
}
在使用 if/while/do/for 表达式时,关键字与开放括号之间不应有空格。就像这样:
while(1) {
/* 永远循环 */
}
在 if/while 条件中,我们更喜欢测试条件值,如布尔值与 TRUE 或 FALSE、指针与 NULL 或 != NULL 以及整数与零或非零,而不是:
result = do_something();
if(!result) {
/* 出现了问题 */
return result;
}
为了增加可读性并减少条件的复杂性,避免在 if/while 条件中进行变量赋值。不赞成这种风格:
if((ptr = malloc(100)) == NULL)
return NULL;
而是鼓励更清晰地表达:
ptr = malloc(100);
if(!ptr)
return NULL;
永远不会在同一行上写多个语句,即使是短的 if() 条件也不例外。
if(a)
return TRUE;
else if(b)
return FALSE;
永远不要这样:
if(a) return TRUE;
else if(b) return FALSE;
请在 C 表达式中运算符的两侧使用空格。后缀 (), [], ->, ., ++, -- 和一元 +, -, !, ~, & 操作符除外,它们不应该有空格。
示例:
bla = func();
who = name[0];
age += 1;
true = !false;
size += -2 + 3 *
(a + b);
ptr->member = a++;
struct.field = b--;
ptr = &address;
contents = *pointer;
complement = ~bits;
empty = (!*string) ? TRUE : FALSE;
在 'return' 语句中不加额外的括号:
int works(void)
{
return TRUE;
}
在代码中使用 sizeof 运算符时,我们更喜欢在其参数周围加上括号:
int size = sizeof(int);
一些语句不能在单行上完成,因为行太长、语句太难读,或者是由于上述其他风格指南。在这种情况下,语句跨越多行。
如果一个连续行是表达式或子表达式的一部分,那么你应该在适当的列上对齐,以便能够清楚地知道它是语句的哪一部分。运算符不应该起始于连续行。在其他情况下,遵循 2 个空格的缩进指南。以下是来自 libcurl 的一些示例:
if(Curl_pipeline_wanted(handle->multi, CURLPIPE_HTTP1) &&
(handle->set.httpversion != CURL_HTTP_VERSION_1_0) &&
(handle->set.httpreq == HTTPREQ_GET ||
handle->set.httpreq == HTTPREQ_HEAD))
/* 没有要求 HTTP/1.0 并且是 GET 或 HEAD 请求 */
return TRUE;
如果没有括号,使用默认缩进:
data->set.http_disable_hostname_check_before_authentication =
(0 != va_arg(param, long)) ? TRUE : FALSE;
函数调用时使用开放括号:
if(option) {
result = parse_login_details(option, strlen(option),
(userp ? &user : NULL),
(passwdp ? &passwd : NULL),
NULL);
}
与 "current open" 括号对齐:
DEBUGF(infof(data, "Curl_pp_readresp_ %d bytes of trailing "
"server response left\n",
(int)clipamount));
使用 #ifdef HAVE_FEATURE 进行条件代码。我们避免在 #ifdef 行中检查特定操作系统或硬件。HAVE_FEATURE 应该由 configure 脚本为类 Unix 系统生成,并且它们在其他系统的 config-[system].h
文件中硬编码。
我们还鼓励在 libcurl 构建时,使用可能为空或定义为常量的宏/函数,以使代码无缝。就像这个例子,其中 magic() 函数根据构建时的条件不同而工作:
#ifdef HAVE_MAGIC
void magic(int a)
{
return a + 2;
}
#else
#define magic(x) 1
#endif
int content = magic(3);
尽管可以使用结构体,但不要对其进行 typedef。使用 struct name
的方式来标识它们:
struct something {
void *valid;
size_t way_to_write;
};
struct something instance;
不要这样:
typedef struct {
void *wrong;
size_t way_to_write;
} something;
something instance;
本文翻译自:https://curl.se/dev/code-style.html