本文档描述 ccsocket 库的编码风格约定,供贡献者和维护者参考。
| 符号类别 | 前缀 | 示例 |
|---|---|---|
| 公开 API 函数 | ccsocket_ |
ccsocket_listen(), ccsocket_set_nodelay() |
| 内部函数 | _ccsocket_ |
_ccsocket_set_flags(), _ccsocket_get_family() |
| 静态函数 / 内部辅助 | ccsocket_ + static |
ccsocket_listen_internal(), ccsocket_wrap_ip_and_port() |
| 类型定义 | ccsocket_ + _t |
ccsocket_t, ccsocket_iovec_t, ccsocket_stcode_t |
| 枚举常量 | CC_ 大写 |
CC_NOFLAG, CC_CLOEXEC, CC_INET4, CC_TCP |
| 宏 | CCSOCKET_ / 全大写 |
CCSOCKET_EXPORT, MAX_ADDRLEN, OPTIONAL |
| 子模块函数 | cc + 模块名 + _ |
ccicmp_init(), cctls_create1() |
| 测试函数 | cctest_ |
cctest_sockpair(), cctest_check_timeout() |
- 函数/变量: 全小写蛇形(snake_case)
int rsize; bool ccsocket_set_nodelay(ccsocket_t s, bool on);
- 类型名: 小写蛇形 +
_t后缀typedef struct ccsocket_iovec { ... } ccsocket_iovec_t; typedef int ccsocket_t;
- 枚举常量: 全大写下划线
CC_OPCODE_OK = 0, CC_OPCODE_WAIT = 1,
- 宏: 全大写下划线
#define MAX_ADDRLEN 255 #define CCSOCKET_EXPORT __attribute__((visibility("default")))
- 结构体成员: 小写蛇形
char address[65]; ccsocket_family_t af; struct ccaddrinfo *next;
2 空格,禁止使用 Tab。
// ✓ 正确
if (flags & CC_NONBLOCK) {
isset = true;
proto_r |= SOCK_NONBLOCK;
}
// ✗ 错误
if (flags & CC_NONBLOCK) {
isset = true; // ← 4空格
proto_r |= SOCK_NONBLOCK;
}- 函数定义: Allman 风格(
{另起一行)
int ccsocket_close(ccsocket_t s)
{
return closesocket(s);
}- 控制语句 (
if/for/while/switch): K&R 风格({跟在行末)
if (s == INVALID_SOCKET) {
ccsocket_close(s);
return false;
}
while (addrlist) {
ccaddrinfo_t *addr = addrlist->next;
free(addrlist);
addrlist = addr;
}- 空函数体: 括号另起一行
void cc_wait() {
while (true) {
cc_usleep(1000);
}
}星号靠近类型名(左结合)或居中,但在同一文件内保持一致。
// ✓ 左结合
void* ptr;
char* buf;
void* ccthread_realloc_t;
// ✓ 或居中
void *ptr;
char *buf;建议不超过 100 字符。超出时在运算符或逗号处合理换行。
ccsocket_dump("WSAStartup init -> {\n\tVer: %g,\n\tmaxVer: %g,\n\t...",
HIBYTE(wsaData.wVersion) + LOBYTE(wsaData.wVersion) * 0.1,
wsaData.iMaxSockets, wsaData.iMaxUdpDg);统一使用 /* */。不允许 //(行尾注释)和 /** */(Doxygen 风格)。
/* close ccsocket */
int ccsocket_close(ccsocket_t s);
/* set the receive timeout (`timeout` in milliseconds). */
CCSOCKET_EXPORT bool ccsocket_set_rcvtimeout(ccsocket_t s, int timeout);枚举值前已有 /* ... */ 块注释描述,因此值本身不附加行尾注释:
/* Used for ccsocket_flags_t: */
typedef enum {
CC_NOFLAG = 0,
CC_CLOEXEC = 1,
CC_NONBLOCK = 2,
} ccsocket_flags_t;使用 /* + * 续行,禁止 /**。
/* enable accept defer in listen tcp socket, becare unless you know it's behavior.
* Support Platform: `Linux` / `FreeBSD` / `Windows`(TODO).
*/
bool ccsocket_enable_accept_defer(ccsocket_t s);功能段间用星号线分隔。
/* ********** Below are some settings that can be used to change the behavior of `ccsocket` ********** */禁止使用 // 注释整段代码。应直接删除;若需保留参考,使用 #if 0 ... #endif。
#if 0
/* send buffer to peer `ccsocket` */
CCSOCKET_EXPORT int ccsocket_sendto(ccsocket_t s, const void *buf, size_t bsize, ...);
#endif使用单下划线风格。
#ifndef CCSOCKET_H
#define CCSOCKET_H
/* ... */
#endif /* CCSOCKET_H */- 包含保护
- 平台导出宏(
CCSOCKET_EXPORT) - 系统头文件
#include - 类型定义(typedef / struct / enum)
- 便捷宏
- 函数声明(按功能分组)
- C++ 兼容
extern "C"块 - 结尾
#endif
#ifdef __cplusplus
extern "C" {
#endif
/* 函数声明 */
#ifdef __cplusplus
}
#endif使用 #if _WIN32(不是 #ifdef WIN32),按平台三路分派。
#if _WIN32
typedef intptr_t ccsocket_t;
#else
typedef int ccsocket_t;
#endif每个 .c 文件顶部定义(后续应抽取到公共头文件):
#if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199409L)
#define CC_INLINE static inline
#elif defined(__cplusplus)
#define CC_INLINE static inline
#elif _MSC_VER >= 1200
#define CC_INLINE static __inline
#else
#define CC_INLINE static
#endif#if _WIN32
#define ccsocket_init_errno() do {errno = 0; WSASetLastError(0);} while(0)
#define ccsocket_is_errno(err) (WSA##err == WSAGetLastError())
#define ccsocket_set_errno(err) do{errno = err; WSASetLastError(WSA##err);} while(0)
#else
#define ccsocket_init_errno() errno = 0
#define ccsocket_is_errno(err) (err == errno)
#define ccsocket_set_errno(err) errno = err
#endif#if _WIN32
#define CCSOCKET_EXPORT __declspec(dllexport)
#else
#define CCSOCKET_EXPORT __attribute__((visibility("default")))
#endif- 布尔函数: 返回
true/false,错误信息通过errno/WSAGetLastError()获取 - 状态码枚举: 使用
ccsocket_stcode_t(CC_OPCODE_OK/CC_OPCODE_ERROR/CC_OPCODE_WAIT)传递操作结果 - 句柄返回: 失败返回
INVALID_SOCKET/NULL/ 负值 - 可选参数: 用
OPTIONAL宏标记可为NULL的指针参数 - EINTR 重试: 被信号中断的系统调用自动重试
ccsocket_stcode_t ccsocket_sendv1(ccsocket_t s, ccsocket_iovec_t *iov,
int iovcnt, OPTIONAL int *wsize, int flags)
{
ccsocket_init_errno();
/* ... 系统调用 ... */
if (w == SOCKET_ERROR) {
if (ccsocket_is_errno(EINTR))
return ccsocket_sendv1(s, iov, iovcnt, wsize, flags); /* 重试 */
if (ccsocket_is_errno(EWOULDBLOCK))
return CC_OPCODE_WAIT;
return CC_OPCODE_ERROR;
}
if (wsize) *wsize = (int)wsz; /* 可选输出指针的 NULL 检查 */
return CC_OPCODE_OK;
}函数入口检查参数合法性,设 errno 后返回。
bool ccsocketpair1(ccsocket_t sv[2], ccsocket_flags_t flags)
{
ccsocket_init_errno();
if (!sv || flags < 0 || flags > 3) {
ccsocket_set_errno(EINVAL);
return false;
}
/* ... */
}- 零初始化: 结构体使用前用
memset清零
struct sockaddr_storage sa;
memset(&sa, 0x0, sizeof(sa));- 栈上 IO 向量: 使用宏初始化和访问
ccsocket_iovec_t iov[1];
ccsocket_init_iov(iov, 1);
ccsocket_set_iov_len(iov, 0, bsize);
ccsocket_set_iov_buf(iov, 0, buf);- 动态内存: 使用标准
malloc/free,失败时清理已分配资源
cur->next = (ccaddrinfo_t*)malloc(sizeof(ccaddrinfo_t));
if (!cur->next) {
freeaddrinfo(addrs);
ccsocket_freeaddrinfo(*addrlist);
*addrlist = NULL;
return false;
}- 宏定义测试用例: 使用
CCSOCKET_TEST_FUNCTION
CCSOCKET_TEST_FUNCTION(cctest_sockpair, {
ccsocket_t sv[2];
bool ok = ccsocketpair(sv, CC_NONBLOCK | CC_CLOEXEC);
assert(ok);
/* ... */
})- 验证: 使用
assert()检查条件 - 输出:
printf("%02d. test case : '%s' successed.\n", ++i, __FUNCTION__) - 命名: 测试函数用
cctest_前缀 + 被测试功能名
| 文件 | 内容 |
|---|---|
ccsocket.h / ccsocket.c |
核心 Socket API |
ccicmp.h / ccicmp.c |
ICMP ping 封装 |
cctls.h / cctls.c |
TLS/SSL 封装(OpenSSL) |
main.c |
测试入口 + 测试用例 |
CMakeLists.txt / premake5.lua / xmake.lua |
构建系统 |
README.md |
项目说明 |
ccsocket.md |
ABI 参考文档 |
STYLE.md |
本文件 — 编码风格指南 |
本文档从 ccsocket 项目实际代码中提取,所有示例均来自真实代码。 贡献前请确保代码符合上述约定。