C 语言企业级命名规范

介绍

良好的命名规范是工程化 C 项目的基石。本文基于嵌入式、Linux、驱动、后台服务等企业级项目通用实践,整理一套可落地、无歧义、团队可直接执行的命名规则。

结论先行

这套规范核心原则:

  • 统一风格,不混用
  • 全局变量 g_、静态变量 s_、指针 p_
  • 常量全大写,类型大驼峰
  • 变量、普通函数小写下划线
  • 全局函数:普通函数前面加 模块名_

命名规范的本质不是约束,而是降低沟通成本、提升可维护性。

1 通用硬性规则

  1. 标识符只能由:英文字母、数字、下划线组成
  2. 不能以数字开头
  3. 严格区分大小写
  4. 不能使用 C 语言关键字(int/char/if/else/enum/struct 等)
  5. 文件名统一:小写 + 下划线
    • 例:main.c、uart_driver.c、sensor_config.h
  6. 禁止拼音、中文、无意义缩写(a/b/tmp 仅允许极短期临时变量)
  7. 禁止下划线与驼峰混用,项目全局统一一种风格

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 企业编码红线

  1. 禁止单个字符命名(循环变量 i/j/k 除外)
  2. 禁止下划线与驼峰混用
  3. 禁止中文、拼音、特殊符号
  4. 全局变量必须加 g_ 前缀,禁止裸奔
  5. 宏、枚举常量必须全大写
  6. 禁止无意义函数名:fun()/test()/do_something()
  7. 同一项目大小写混乱:Uart/uart/UART 混用
  8. 禁止使用下划线开头命名(易与系统内部符号冲突)

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;