介绍
良好的命名规范是工程化 C 项目的基石。本文基于嵌入式、Linux、驱动、后台服务等企业级项目通用实践,整理一套可落地、无歧义、团队可直接执行的命名规则。
结论先行
这套规范核心原则:
- 统一风格,不混用
- 全局变量
g_、静态变量s_、指针p_ - 常量全大写,类型大驼峰
- 变量、普通函数小写下划线
- 全局函数:普通函数前面加
模块名_
命名规范的本质不是约束,而是降低沟通成本、提升可维护性。
1 通用硬性规则
- 标识符只能由:英文字母、数字、下划线组成
- 不能以数字开头
- 严格区分大小写
- 不能使用 C 语言关键字(
int/char/if/else/enum/struct等) - 文件名统一:小写 + 下划线
- 例:
main.c、uart_driver.c、sensor_config.h
- 例:
- 禁止拼音、中文、无意义缩写(
a/b/tmp仅允许极短期临时变量) - 禁止下划线与驼峰混用,项目全局统一一种风格
2 推荐统一风格(企业最常用)
C 语言主流风格:下划线命名法(snake_case)
- 变量、函数、文件:
student_count、uart_init - 宏、枚举常量:全大写 + 下划线
- 结构体/typedef:大驼峰(PascalCase)
3 变量命名规范
3.1 局部变量
- 小写 + 下划线
- 见名知意,简洁清晰
int count; int buffer_len; char user_name[32];
3.2 全局变量
- 规则:必须加
g_前缀 - 目的:一眼识别全局,避免与局部变量冲突
int g_system_status; int g_uart_fd; char g_recv_buffer[1024];
3.3 静态全局 / 静态局部变量
- 规则:加
s_前缀static int s_init_flag; static int s_cache_size;
3.4 指针变量
- 建议加
p_前缀,明确是指针char *p_data; int *p_len; struct Student *p_stu;
3.5 布尔/状态标志
- 以
is_/has_/enable_开头int is_ready; int has_error; int enable_uart;
4 常量与宏
4.1 #define 宏
- 全大写 + 下划线
#define MAX_BUFFER_SIZE 1024 #define UART_BAUDRATE 115200
4.2 const 常量
- 推荐同宏风格:全大写 + 下划线
const int MAX_CLIENT_NUM = 10; const char DEVICE_NAME[] = "uart0";
5 函数命名
- 小写 + 下划线
动词开头,语义清晰
void system_init(void); int uart_send(const char *p_data, int len); int sensor_get_value(void);静态函数:可加模块前缀,避免污染全局命名空间
static int check_param_valid(int param);
全局函数
全局函数 = 模块名前缀 + 下划线 + 功能名
这是嵌入式 / Linux / 驱动 / 后台服务最标准的写法。
格式
返回值 模块名_功能名(参数);
示例
// UART 模块
void uart_init(void);
int uart_send_data(char *buf, int len);
// LED 模块
void led_on(void);
void led_off(void);
// 系统模块
void system_reset(void);
int system_get_version(void);
为什么要加模块前缀?
因为全局函数是整个工程可见的。
不加前缀,很容易出现函数重名冲突!
例如:
// 两个文件都写 init() → 编译报错!重复定义
void init(void);
所以企业规范强制:
全局函数必须带模块前缀
6 结构体、枚举、typedef
6.1 结构体
- 大驼峰
typedef struct { int id; char name[32]; int age; } StudentInfo;
6.2 枚举
- 类型:大驼峰
- 枚举值:全大写 + 下划线
typedef enum { STATUS_OK = 0, STATUS_ERROR_PARAM, STATUS_ERROR_TIMEOUT } StatusCode;
6.3 类型别名
- 大驼峰
typedef unsigned char Uint8; typedef unsigned int Uint32;
7 企业编码红线
- 禁止单个字符命名(循环变量
i/j/k除外) - 禁止下划线与驼峰混用
- 禁止中文、拼音、特殊符号
- 全局变量必须加
g_前缀,禁止裸奔 - 宏、枚举常量必须全大写
- 禁止无意义函数名:
fun()/test()/do_something() - 同一项目大小写混乱:
Uart/uart/UART混用 - 禁止使用下划线开头命名(易与系统内部符号冲突)
8 完整示例
#include <stdio.h>
#define MAX_STUDENT 50
typedef enum {
STATUS_OK = 0,
STATUS_ERROR
} StatusCode;
typedef struct {
int id;
char name[32];
} StudentInfo;
static int s_student_count = 0;
int g_system_running = 1;
StatusCode add_student(StudentInfo *p_stu) {
if (s_student_count >= MAX_STUDENT) {
return STATUS_ERROR;
}
s_student_count++;
return STATUS_OK;
}
int main(void) {
StudentInfo stu = {1, "zhangsan"};
StatusCode ret = add_student(&stu);
printf("ret = %d\n", ret);
return 0;
}
单片机常用大驼峰
因为:
- STM32 HAL/LL库:
HAL_GPIO_TogglePin() - Arduino:
digitalWrite() - RT-Thread:
rtDeviceFind() - Keil、ARM 官方示例:大量大驼峰
这些库为了辨识度高、和底层 C 区分开,普遍使用:
大驼峰 / 小驼峰
所以:
单片机项目用驼峰,完全正确、非常常见。
哪种命名是对的?
一句话总结:没有唯一正确,只有“项目统一”。
但行业有两大主流派系:
派系1:Linux / 驱动 / 底层 C → 下划线 snake_case
- 全局函数:
uart_init() - 变量:
rx_buffer_len
派系2:单片机 / STM32 / Arduino / 嵌入式GUI → 驼峰
- 全局函数:
UartInit()、halGpioInit() - 变量:
rxBufferLen
如果项目偏底层 / Linux / 裸机驱动
→ 用 下划线
void uart_init(void);
int g_system_status;
如果项目基于 STM32 HAL / Arduino / RTOS
→ 跟随库风格,用 驼峰
void Uart_Init(void);
void UartInit(void);
int gSystemStatus;