尧图网络科技YAOTU DIGITAL 获取报价
获取报价
首页 / 资讯中心 / 文章详情

curl C 代码风格指南:从规范到 checksrc 自动化检查的完整实战

发布时间:2026/9/11 15:24:25

资讯中心
01
ARTICLE

curl C 代码风格指南:从规范到 checksrc 自动化检查的完整实战

curl C 代码风格指南:从规范到 checksrc 自动化检查的完整实战
curl C 代码风格指南从规范到 checksrc 自动化检查的完整实战【免费下载链接】curlA command line tool and library for transferring data with URL syntax, supporting DICT, FILE, FTP, FTPS, GOPHER, GOPHERS, HTTP, HTTPS, IMAP, IMAPS, LDAP, LDAPS, MQTT, MQTTS, POP3, POP3S, RTSP, SCP, SFTP, SMB, SMBS, SMTP, SMTPS, TELNET, TFTP, WS and WSS. libcurl offers a myriad of powerful features项目地址: https://gitcode.com/GitHub_Trending/cu/curlcurl 是一个拥有数十年历史的开源项目其 C 代码库横跨 libcurl 库、命令行工具与测试框架长期由大量贡献者协作维护。为了让代码读起来像同一套代码项目在 docs/internals/CODE_STYLE.md 中固化了一套严格的 C89 代码风格规范并通过 scripts/checksrc.pl 脚本在构建时自动执行检查。本文以该风格文档为骨架完整梳理 curl 的代码风格规则并结合仓库源码与构建系统说明其落地方式帮助贡献者在提交代码前写出风格合规、零警告的 C 代码。为什么 curl 需要一套统一的代码风格统一风格的价值远不止好看。代码风格一致能显著降低阅读与维护成本可读性是第一特性代码的意图必须对读者可见清晰无歧义比聪明地省两行代码更重要。curl 项目强调写简单代码让未来十年里回来调试的人能快速看懂。降低评审与调试成本新代码评审、Bug 定位时统一的格式让 diff 更干净、问题更容易暴露。统一胜过个人偏好项目明确表态统一风格比满足个别贡献者的个人品味更重要。这些规则中大部分由 scripts/checksrc.pl 脚本自动校验可通过make checksrc手动运行也可在./configure --enable-debug之后由构建系统在编译时默认执行。此外curl 还要求代码在尽可能多的主流平台上零编译警告产生警告的代码不会被原样接受。命名规范清晰、小写、静态化新函数与变量命名应逻辑清晰、按用途命名不必强求与其他位置一致但要可理解。文件内部的函数必须声明为static。项目偏好小写命名。对于库内导出的、非全局可见的符号curl 有专门的命名约定见 docs/internals/README.md 中关于内部文档的说明。从源码结构看libcurl 内部大量函数以Curl_前缀标识内部全局符号例如登录信息解析函数Curl_parse_login_details()在 lib/url.h 声明、在 lib/url.c 实现并被 lib/setopt.c 与 lib/urlapi.c 多处调用。这种前缀约定让库内符号与公开 API 一目了然地区分开来。排版基础缩进、注释与行长只用空格缩进两级一档curl 代码禁止使用 TAB每级缩进为两个空格if(something_is_true) { while(second_statement fine) { moo(); } }注释只能用/* ... */curl 坚持编写C89 代码而//行注释直到 C99 才进入标准因此一律禁止//注释只能使用/* comment */形式/* this is a comment */行长不得超过 79 列源码宽度永远不允许超过 79 列即使在宽屏时代依然如此原因有二窄列比宽列更易读——报纸分栏排版沿用数百年的道理窄列允许开发者在同一屏幕上并排打开两三个源码窗口、多个终端与调试窗口。对应地checksrc的LONGLINE警告会检测超过 79 列的行这一上限在 scripts/checksrc.pl 中定义为my $max_column 79;。控制流与花括号位置决定可读性if/while/do/for 的花括号在if/while/do/for表达式中开括号{与关键字同行闭括号与关键字同缩进级别对齐if(age 40) { /* clearly a youngster */ }若块内只有一条单行语句可省略花括号if(!x) continue;函数的花括号单独占一行与普通控制流不同函数的开括号应独占一行int main(int argc, char *argv[]) { return 1; }else 必须另起一行带花括号的else子句要写在闭括号之后的新行上if(age 40) { /* clearly a youngster */ } else { /* probably grumpy */ }这与许多项目} else {的写法不同checksrc的BRACEELSE警告专门检查这一规则。关键字与左括号之间不留空格if/while/do/for与左括号之间不得有空格while(1) { /* loop forever */ }对应警告为SPACEBEFOREPAREN检测if (这类写法。条件用布尔语义表达在if/while条件中不要显式与TRUE/FALSE、NULL/! NULL、0/! 0比较直接使用布尔语义result do_something(); if(!result) { /* something went wrong */ return result; }checksrc的EQUALSNULL与NOTEQUALSZERO警告分别拦截 NULL与! 0的写法。禁止在条件内赋值为提高条件表达式的可读性、降低复杂度禁止在 if/while 条件中赋值。这种写法被明确反对if((ptr malloc(100)) NULL) return NULL;应拆开书写ptr malloc(100); if(!ptr) return NULL;checksrc的ASSIGNWITHINCONDITION警告对应此规则。新块必须换行禁止单行多条语句同一源码行内绝不写多条语句即使是很短的if()条件if(a) return TRUE; else if(b) return FALSE;而绝不允许if(a) return TRUE; else if(b) return FALSE;对应警告为ONELINECONDITION。表达式与运算符留白有讲究运算符两侧留空格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;checksrc的EQUALSNOSPACE、NOSPACEEQUALS、MULTISPACE、EXCLAMATIONSPACE等警告都在守护这些细节。类型转换与表达式贴紧curl 尽量回避类型转换不得不使用时类型转换与后面的表达式之间不留空格int value (int)foobar; char *ptr (char *)random_func();return 不加括号sizeof 必须加括号return语句的值不加多余括号int works(void) { return TRUE; }而sizeof必须带括号int size sizeof(int);checksrc的RETURNNOSPACE与SIZEOFNOPAREN分别检测这两种情况。列对齐长表达式的续行规范当语句因过长、难读或风格限制必须跨多行时表达式或子表达式的续行应与所属列对齐方便看出它是语句的哪一部分续行不能以运算符开头其他情况遵循两级空格缩进。文档中给出 libcurl 真实代码的四种典型续行模式1. 括号表达式按括号内侧对齐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)) /* did not ask for HTTP/1.0 and a GET or HEAD */ return TRUE;2. 无括号时使用默认缩进data-set.http_disable_hostname_check_before_authentication va_arg(param, long) ? TRUE : FALSE;3. 函数调用以开括号为对齐基准if(option) { result parse_login_details(option, strlen(option), (userp ? user : NULL), (passwdp ? passwd : NULL), NULL); }这个示例中的parse_login_details在仓库中对应的真实函数是Curl_parse_login_details()其参数表login、len、userp、passwdp、optionsp在 lib/url.c 有完整注释它用于解析user、user:password、user:password;options等登录字符串格式是 libcurl 处理 URL 与 setopt 登录参数的核心工具。4. 与当前打开的括号对齐DEBUGF(infof(data, Curl_pp_readresp_ %d bytes of trailing server response left\n, (int)clipamount));对应警告为INDENTATION注意它只检查特定位置难免漏检。平台相关代码用 HAVE_FEATURE 而非平台判断平台相关代码应使用#ifdef HAVE_FEATURE做条件编译避免在#ifdef中直接判断特定操作系统或硬件。HAVE_FEATURE宏在类 Unix 系统上由 configure 脚本生成在其他系统上则硬编码在config-[system].h文件中如 lib/config-win32.h、lib/config-mac.h 等。同时鼓励使用在功能未编译时可退化为空或常量的宏/函数让代码在不同构建配置间无缝衔接。例如magic()依据编译期条件产生不同行为#ifdef HAVE_MAGIC void magic(int a) { return a 2; } #else #define magic(x) 1 #endif int content magic(3);结构体用 struct name禁用 typedef可以使用结构体但不要为其 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;对应警告为TYPEDEFSTRUCT。禁用函数清单从源头避免脚枪为避免踩坑与意外后果curl禁止使用一批 C 函数checksrc脚本发现使用会直接报错BANNEDFUNC警告。在 scripts/checksrc.pl 中这些函数以%banfunc哈希表形式硬编码与文档中的清单完全一致。完整清单如下_access _fstati64 _lseeki64 _mbscat _mbsncat _open _tcscat _tcsdup _tcsncat _tcsncpy _waccess _wcscat _wcsdup _wcsncat _wfopen _wfreopen _wopen abort accept accept4 access aprintf assert atoi atol calloc close CreateFile CreateFileA CreateFileW fclose fdopen fopen fprintf free freeaddrinfo freopen fstat getaddrinfo gets gmtime inet_ntop inet_pton llseek LoadLibrary LoadLibraryA LoadLibraryEx LoadLibraryExA LoadLibraryExW LoadLibraryW localtime lseek malloc mbstowcs MoveFileEx MoveFileExA MoveFileExW msnprintf mvsnprintf open printf realloc recv rename send snprintf socket socketpair sprintf sscanf stat strcat strcpy strdup strerror strncat strncpy strtok strtok_r strtol strtoul vaprintf vfprintf vprintf vsnprintf vsprintf wcscpy wcsdup wcsncpy wcstombs WSASocket WSASocketA WSASocketW这些函数大多有安全替代品例如内存分配与释放统一走 curl 内部的curl_malloc/curl_free等包装与curlx_safefree()安全释放USESAFEFREE警告鼓励用curlx_safefree(var)取代curlx_free(var)后紧跟赋 NULL的两步写法snprintf被替换为返回码语义不同的内部版本curl_msnprintfSNPRINTF警告strerror、stderr也在扩展警告中被禁止。checksrc让风格检查自动化检查的触发方式手动运行仓库根目录执行make checksrc该目标在顶层 Makefile.am 中定义会依次进入lib、src、tests、include/curl、docs/examples、projects等目录执行检查。构建时自动运行使用./configure --enable-debug配置后构建系统会在编译时默认执行 checksrc见 lib/Makefile.am 中的checksrc:目标它通过PERL $(top_srcdir)/scripts/checksrc.pl -D$(srcdir) $(CSOURCES) $(HHEADERS)对全部源文件与头文件执行扫描。命令行用法checksrc.pl [options] [file1] [file2] ...-W[file]跳过指定文件不检查常用于生成的文件-D[dir]访问文件时前置的目录名-h显示帮助同时列出所有可识别的警告。checksrc 检查什么checksrc并不校验全部风格规则而是着力于捕获贡献者最常见的格式与语法错误。其全部告警的权威清单见 docs/internals/CHECKSRC.md与本文各节规则一一对应例如警告含义对应风格规则ASSIGNWITHINCONDITION条件表达式内赋值禁止在条件内赋值ASTERISKNOSPACE/ASTERISKSPACE指针声明char* name/char * name星号应紧贴变量名BANNEDFUNC使用了禁用函数禁用函数清单BRACEELSE} else同行else 另起一行BRACEPOS开括号位置错误花括号位置COMMANOSPACE逗号后无空格运算符空格CPPCOMMENTS出现//注释只用/* */EQUALSNULL使用 NULL比较用!varFOPENMODEcurlx_fopen()模式串未用宏平台相关代码LONGLINE行宽超过 79 列行长限制NOTEQUALSZERO使用! 0用if(var)ONELINECONDITIONif()与块同行新块换行SIZEOFNOPARENsizeof未加括号sizeof 加括号SNPRINTF使用了snprintf()用curl_msnprintf()SPACEBEFOREPAREN关键字后、括号前有空格括号前无空格TABS出现 TAB 字符只用空格缩进TRAILINGSPACE行尾空白排版整洁TYPEDEFSTRUCTtypedef 结构体禁用 typedef structUNUSEDIGNORE内联忽略指令未被使用忽略指令应被用上USESAFEFREEcurlx_free()后跟赋 NULL用curlx_safefree()扩展警告按目录启用部分警告计算开销较大默认关闭。可在需要启用的目录下放置.checksrc文件每行一个指令启用格式为enable EXTENDEDWARNING目前可启用的扩展警告包括COPYRIGHTYEAR当前改动未更新源文件中的版权年份STRERROR使用了禁用函数strerror()STDERR使用了禁用变量stderr。.checksrc的解析逻辑包括enable/disable指令处理可在 scripts/checksrc.pl 中看到。如何豁免个别警告由于源码特性和工具本身的局限有时需要豁免特定警告checksrc提供两种途径1. 内联忽略推荐在源码文件内通过注释指令控制仅对该文件生效。忽略某警告直到重新启用/* !checksrc! disable LONGLINE all */之后用以下指令重新启用文件结束前未启用则下一个文件自动恢复/* !checksrc! enable LONGLINE */也可以只忽略 N 次违规精确控制豁免范围例如某个确实无法缩短且被认可的长行/* !checksrc! disable LONGLINE 1 */次数用完自动重新启用确保只忽略预期的实例。若写了忽略指令却没用上UNUSEDIGNORE会提示移除或修正。2. 目录级跳过文件已弃用在出现误报的源码目录下创建checksrc.skip文件把完整违规行写入其中。这是旧方法项目已转向尽量使用内联忽略。实战要点让新代码一次通过综合风格文档与 checksrc 工具贡献者提交前可快速自查编辑器先行将编辑器设置为空格缩进每级 2 空格、禁止 TAB、显示 79 列标尺从源头避免TABS、LONGLINE、INDENTATION用 C89 心智写代码注释只用/* */变量声明遵循 C89 约束遵循控制流模板if/else、循环、函数的花括号位置与换行方式直接参考上文模板else单独成行善用布尔条件if(!ptr)、if(result)拒绝 NULL、! 0、条件内赋值内存与字符串安全绕开禁用函数清单使用 curl 内部的curl_msnprintf、curlx_safefree等替代品提交前跑一遍执行make checksrc或基于--enable-debug构建让检查自动生效遇到确需豁免的个别情况用/* !checksrc! disable WARN N */精确豁免并确保其被真正使用。将以上规则内化为习惯后写出的代码不仅风格统一、易于评审还能与 curl 整个代码库无缝融合——这正是这份风格指南与 checksrc 工具存在的意义让数十年的协作代码始终像出自同一人之手。延伸阅读风格检查工具的完整告警清单见 docs/internals/CHECKSRC.md检查脚本实现见 scripts/checksrc.pl风格文档原文见 docs/internals/CODE_STYLE.md。【免费下载链接】curlA command line tool and library for transferring data with URL syntax, supporting DICT, FILE, FTP, FTPS, GOPHER, GOPHERS, HTTP, HTTPS, IMAP, IMAPS, LDAP, LDAPS, MQTT, MQTTS, POP3, POP3S, RTSP, SCP, SFTP, SMB, SMBS, SMTP, SMTPS, TELNET, TFTP, WS and WSS. libcurl offers a myriad of powerful features项目地址: https://gitcode.com/GitHub_Trending/cu/curl创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
02
RELATED NEWS

相关资讯

更多网站建设与数字化升级内容

03
WHY YAOTU

想打造同款高转化官网?

懂行业、懂生意,从建站到增长一站式陪跑

场景化定制

不做模板站,围绕你的业务场景量身设计,小众不撞款。

营销型架构

以转化目标组织内容与路径,让官网真正带来询盘。

全周期服务

设计、开发、运营、运维一体,上线只是开始。

免费获取你的建站方案

留下需求,专属顾问 24 小时内为你输出方案建议。