1. 注释

所有的注释统一使用 /**/,除了一些特殊的注释以外。

单行注释:

1
/* 单行注释 */

多行注释:

1
2
3
4
/**
 * 多行注释 1
 * 多行注释2
 */

特殊的注释:用于表面一些待办事项,比如:TODO、FIXME、BUG、HACK。

1
2
// TODO 实现 xxx 功能
// FIXME 需修复 xxx 功能

特殊的注释:在第三方 SDK 中加入修改,并方便后续升级 SDK 时方便区分。

1
2
3
4
5
6
7
8
// [公司名] [人名] [时间] S : 实现 xxx 功能
...
// [公司名] [人名] [时间] E : 实现 xxx 功能


// Github Zeepunt 2025.10.01 S: 添加调试打印信息
...
// Github Zeepunt 2025.10.01 E: 添加调试打印信息

2.大括号

对于所有非函数的语句块,把起始大括号放在行尾,而把结束大括号放在行首。

例如:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
if (var == 0) {
    var = 1;
    var++;
}

switch (num) {
    case NUM_ONE:
        return 1;

    case NUM_TWO:
        return 2;

    default:
        return 0;
}

do {
    printf("1\r\n");
} while(1);

对于函数来说,函数的起始大括号放置于下一行的开头。

例如:

1
2
3
4
int function(void)
{
    return 0;
}

当只有一个单独的语句的时候,也需要加大括号。

例如:

1
2
3
4
5
6
7
if (var == 0) {
    return false;
}

for (uint i = 0; i < 32; i++) {
    printf("i: %d.\n", i);
}

3. 空格

大多数关键字之后放一个空格。

例如:

1
if, switch, case, for, do, while

当声明指针类型或者返回指针类型的函数时, * 的首选使用方式是使之靠近变量名或者函数名,而不是靠近类型名。

例如:

1
2
3
char *var = NULL;
void sum(int *a, int *b);
char *get_char(char *str);

4. 变量命名

对于仅用于当前文件的内部变量,可以使用以下两种方式的命名:

1
2
3
4
5
6
7
8
/* 以 s_ 开头, 表示全局内部变量 */
static int s_var = 0;

/* 以 _ 开头, 表示函数内部变量 */
void func(void)
{
    static char _module_name = "xxx";
}

对于全局变量来说,命名方式为:

1
2
3
4
/* 以 g_ 开头, 表示全局变量 */
int g_version = 0x0200;

extern int g_version;

5. 类型声明

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
/**
 * 结构体以 _s 结尾, 表示 struct
 * 枚举以 _e 结尾, 表示 enum
 * 联合体以 _u 结尾, 表示 union
 * 如果使用 typedef 类型声明, 则以 _t 结尾, 表示 typedef
 */

typedef struct dev_info_s {
    int dev_num;
} dev_info_t;

typedef enum dev_type_e {
    DEV_TYPE_CHAR,
} dev_type_t;

typedef union dev_board_u {
    uint16_t data;
    struct {
        uint8_t var1;
        uint8_t var2;
    } d;
} dev_board_t;

typedef void (*dev_notify_t)(void *arg);

6. 函数命名

可以对外声明的函数命名格式为:层级 + 模块名 + 名词 + 动词。

仅对内声明的函数命名格式为:priv + 模块名 + 名称 + 动词。

1
2
3
4
5
6
/* Driver 的 uart 模块 */
int drv_uart_buf_send(uint8_t *buf, uint32_t buf_len);
int drv_uart_buf_recv(uint8_t *buf, uint32_t buf_len);

static void priv_uart_buf_hander(uint8_t *buf, uint32_t buf_len)
static void priv_uart_buf_init(void);

7. 函数调用

如果调用的函数有返回值,那么有两种调用方式:

1
2
3
4
5
6
7
int ret = 0;

/* 方式一: 获取 test_func 函数的返回值 */
ret = test_func();

/* 方式二: 明确告知编译器"忽略返回值", 避免相关警告, 比如 -Wunused-result */
(void)test_func();

这两种调用方式所实现的功能是一样的。

8. 字符串和缓冲区

字符串使用的 char * 来声明。

用于存放数据的缓冲区使用 uint8_t * 来声明。

1
2
3
char *str = "AABBCCDDEEFF";

uint8_t *buf[3] = {0x11, 0x22, 0x33};

版权声明

本文为「Zeepunt 日常随笔」的原创文章,遵循 CC 4.0 BY-SA 版权协议。

原文链接:https://zeepunt.github.io/article/c/c%E4%B8%AA%E4%BA%BA%E4%BB%A3%E7%A0%81%E9%A3%8E%E6%A0%BC%E8%A7%84%E8%8C%83/