【C命名规范】遵循良好的命名规范,提高代码的可读性、可维护性和可复用性

发布于:2024-07-02 ⋅ 阅读:(14) ⋅ 点赞:(0)
/********************************************************************
* @brief @param @return @author @date @version是代码书写的一种规范
* @brief :简介,简单介绍函数作用
* @param :介绍函数参数
* @return:函数返回类型说明
* @exception NSException 可能抛出的异常.
* @author zhangsan: 作者
* @date 2011-07-27 22:30:00 :时间
* @version 1.0 :版本
* @property :属性介绍
* *********************************************************************/


【变量的命名习惯】
变量名是自定义的,严格遵循 标识符 命名规则。

  • 见名知意
  • 大驼峰:即每个单词首字母都大写,例如:MyName
  • 小驼峰:即第二个(含)以后的单词首字母大写,例如:myName
  • 小写+下划线:例如:my_name

个人风格分享

1.变量

  • 全局变量:小驼峰(小驼峰+下划线),例如 myNamemy_Name

  • 局部变量: 全小写(小写+下划线),例如 indexmy_name

2.常量: 全大写字母、下划线分隔单词和描述性名称

#define MAX_BUFFER_SIZE 1024
#define PI_VALUE 3.14159
#define DEFAULT_TIMEOUT 30

3.标志变量

  • 全局:g_ + 小驼峰 + 下划线,例如 g_has_Err
  • 局部: g_ + 全小写 + 下划线 , 例如 g_has_err

4.函数名 大驼峰(大驼峰+下划线), 例如 GetValue, Get_Value()

动词+名词结构 ,例如 GetValue, Get_Value()

5.结构体 大驼峰(大驼峰 + 下划线),例如

// 定义结构体
typedef struct {
    int id;   // 结构体成员局部的用小写
    char name[50];
    int age;
} StudentInfo;
// Student_Info

6.枚举 : 枚举成员名使用全大写字母, 前缀标识枚举成员

typedef enum {
    STATUS_SUCCESS, // 前缀标识枚举成员
    STATUS_ERROR,  // 全大写字母
    STATUS_PENDING
} StatusCode;
// Status_Code;

总结就是凡是有带大写的都跟全局有关,凡是标志位够加g_,常量用全大写字母表示。


在C语言编程中,良好的命名规则有助于提高代码的可读性可维护性可扩展性。以下是一些值得学习和遵守的命名规则:

  1. 变量命名规则:

    • 使用小写字母,单词之间用下划线分隔,例如:student_age, total_sumindex
    • 变量名应具有描述性,反映其用途或含义。
  2. 常量命名规则:

    • 使用全大写字母,单词之间用下划线分隔,例如:MAX_BUFFER_SIZE, PI_VALUE
    • 常量名通常使用 #defineconst 关键字定义。
  3. 函数命名规则:

    • 使用动词或动词短语开头,后接名词,单词之间用下划线分隔,例如:calculate_sum, print_student_info
    • 函数名应清晰描述其功能或操作。
  4. 结构体和联合体命名规则:

    • 结构体和联合体类型名使用大写字母开头,每个单词的首字母大写,例如:StudentInfo, EmployeeRecord
    • 结构体变量名使用小写字母,单词之间用下划线分隔,例如:student_info, employee_record
  5. 枚举命名规则:

    • 枚举类型名使用大写字母开头,每个单词的首字母大写,例如:Color, Status
    • 枚举成员名使用全大写字母,单词之间用下划线分隔,例如:RED, GREEN, SUCCESS, FAILURE
  6. 文件名规则:

    • 文件名应简洁且具有描述性,通常使用小写字母,单词之间用下划线分隔,例如:main.c, student_info.h
  7. 缩写和简写:

    • 尽量避免使用不常见的缩写和简写,如果使用缩写,确保其含义清晰并在代码中有解释。
  8. 命名长度:

    • 命名长度应适中,过长的名字会影响可读性,过短的名字则可能不够描述性。一般推荐变量名长度在3-20个字符之间。
  9. 前缀和后缀:

    • 使用前缀或后缀区分不同作用域或用途的变量,例如:全局变量使用 g_ 前缀,静态变量使用 s_ 前缀,指针变量使用 _ptr 后缀。

通过遵守这些命名规则,可以使代码更具可读性和可维护性,减少出错的概率。


全局变量的标志位变量命名时,应该遵循一些具体的规则,以确保代码的可读性和易维护性。以下是一些建议:

  1. 使用前缀标识全局变量:

    • g_ 前缀来标识全局变量。例如:g_flag_connected, g_flag_initialized
  2. 清晰描述变量含义:

    • 变量名应反映其用途或含义。使用描述性单词使其一目了然。例如:g_flag_error_occurred, g_flag_data_ready
  3. 使用布尔命名约定:

    • 对于布尔类型的标志位变量,使用 is, has, can 等前缀。例如:g_is_connected, g_has_error, g_can_read
  4. 统一命名风格:

    • 保持命名的一致性,确保团队中所有开发者遵循相同的命名规范。例如:所有标志位变量都以 g_flag_ 开头,然后描述具体含义。
  5. 避免使用缩写:

    • 除非是非常常见和容易理解的缩写,否则尽量避免使用缩写,以防止误解。例如:g_flag_buffer_overflow 而不是 g_flag_buf_ovf
  6. 示例命名:

    • g_flag_initialized - 表示系统或模块是否已初始化。
    • g_flag_error_occurred - 表示是否发生了错误。
    • g_flag_data_ready - 表示数据是否已经准备好。
    • g_is_connected - 表示是否已经连接。
    • g_has_data - 表示是否有数据可用。

通过遵守这些命名规则,可以使代码更具可读性和一致性,方便团队协作和代码维护。


在单片机开发中,良好的编程习惯和命名规则可以极大地提高代码的可读性、可维护性和可靠性。以下是一些值得学习和遵守的编程习惯和命名规则:

编程习惯

  1. 注释代码:

    • 在代码中添加必要的注释,解释代码的功能、逻辑和重要的变量或函数。确保注释清晰且有意义。
  2. 模块化编程:

    • 将代码划分为多个模块或文件,每个模块负责特定的功能。这样可以提高代码的可维护性和可复用性。
  3. 使用常量和宏定义:

    • 使用 #defineconst 定义常量,避免在代码中使用硬编码的数值。例如:#define MAX_BUFFER_SIZE 1024
  4. 初始化所有变量:

    • 在使用变量之前进行初始化,以防止未定义行为和潜在的错误。
  5. 防御性编程:

    • 编写健壮的代码,处理所有可能的错误情况和异常情况。使用断言(assert)来捕捉不应出现的条件。
  6. 合理使用中断:

    • 中断服务程序(ISR)应该尽量短小精悍,避免在ISR中执行耗时操作。将复杂的处理移到主程序中完成。
  7. 遵循代码规范:

    • 遵循团队或项目的编码规范,确保代码风格一致。常见的编码规范包括命名规则、缩进风格、括号位置等。

命名规则

  1. 变量命名:

    • 使用描述性名称,避免使用单个字符或无意义的名称。变量名应反映其用途或含义。
    • 使用小写字母,单词之间用下划线分隔。例如:sensor_value, motor_speed
  2. 常量命名:

    • 使用全大写字母,单词之间用下划线分隔。例如:MAX_BUFFER_SIZE, PI_VALUE
  3. 函数命名:

    • 使用动词或动词短语开头,后接名词,单词之间用下划线分隔。例如:init_motor, read_sensor_value
  4. 结构体和枚举命名:

    • 结构体和枚举类型名使用大写字母开头,每个单词的首字母大写,例如:SensorData, ErrorCode
    • 结构体变量名使用小写字母,单词之间用下划线分隔,例如:sensor_data, error_code
  5. 宏定义命名:

    • 使用全大写字母,单词之间用下划线分隔。例如:#define LED_PIN 13, #define TIMER_PERIOD 1000
  6. 文件命名:

    • 文件名应简洁且具有描述性,通常使用小写字母,单词之间用下划线分隔,例如:main.c, sensor_driver.h

代码示例

// 常量和宏定义
#define MAX_BUFFER_SIZE 1024
#define LED_PIN 13

// 结构体定义
typedef struct {
    int sensor_value;
    float temperature;
} SensorData;

// 函数声明
void init_motor(void);
int read_sensor_value(void);

// 主函数
int main(void) {
    // 变量初始化
    SensorData sensor_data = {0, 0.0};
    int sensor_value = 0;

    // 初始化电机
    init_motor();

    // 读取传感器值
    sensor_value = read_sensor_value();

    // 处理传感器数据
    sensor_data.sensor_value = sensor_value;
    sensor_data.temperature = sensor_value * 0.1;

    return 0;
}

// 函数定义
void init_motor(void) {
    // 初始化电机的代码
}

int read_sensor_value(void) {
    // 读取传感器值的代码
    return 42;
}

这些编程习惯和命名规则可以帮助你编写更高质量、更易维护的代码,尤其是在团队协作和长期维护中显得尤为重要。


在编程中,断言(assert)是一种用于捕捉不应出现的条件的调试工具。断言可以在开发和调试过程中帮助检测程序中的逻辑错误和不一致性。当程序运行时,如果断言条件为假(false),程序会立即终止,并输出错误信息,方便开发者定位和修复问题。

使用断言的步骤

  1. 包含头文件:

    • 使用断言前,需要包含头文件 <assert.h>
  2. 使用 assert 宏:

    • 使用 assert 宏来检查条件。语法如下:
      #include <assert.h>
      
      void some_function(int value) {
          assert(value > 0); // 如果 value <= 0,程序将终止并输出错误信息
      }
      
  3. 编译时控制:

    • 断言在调试阶段非常有用,但在发布阶段可能不需要。可以通过定义 NDEBUG 来禁用断言。
      #define NDEBUG
      #include <assert.h>
      

示例代码

以下是一个使用断言的示例代码:

#include <assert.h>
#include <stdio.h>

// 计算数组中元素的平均值
double calculate_average(int *array, int size) {
    // 断言数组指针不为空
    assert(array != NULL);

    // 断言数组大小大于0
    assert(size > 0);

    int sum = 0;
    for (int i = 0; i < size; i++) {
        sum += array[i];
    }
    return (double)sum / size;
}

int main() {
    int values[] = {10, 20, 30, 40, 50};
    int size = sizeof(values) / sizeof(values[0]);

    // 调用函数前的断言
    assert(size > 0);

    double average = calculate_average(values, size);
    printf("Average: %.2f\n", average);

    return 0;
}

解释

  1. 包含头文件:

    • 代码中首先包含了 <assert.h> 头文件,这个头文件定义了 assert 宏。
  2. 使用 assert 宏:

    • calculate_average 函数中,使用了两个断言来确保输入的数组指针不为空且数组大小大于0。
    • main 函数中,使用了一个断言来确保数组大小大于0。
  3. 断言失败:

    • 如果 assert 条件为假,程序将终止并输出错误信息,包括断言失败的条件和源代码文件中的行号。

禁用断言

在发布阶段,可以通过定义 NDEBUG 来禁用断言。例如:

#define NDEBUG
#include <assert.h>

在定义 NDEBUG 后,所有 assert 语句将被预处理器移除,断言检查将不会在程序运行时执行。

总结

使用断言可以有效地捕捉程序中不应出现的条件,帮助开发者在调试阶段快速定位和修复逻辑错误。通过合理使用断言,可以提高代码的健壮性和可靠性。在发布阶段,可以通过定义 NDEBUG 来禁用断言,确保程序的性能和稳定性。


在项目中使用单片机的多个串口(如串口0、串口1、串口2)进行数据收发时,可以使用结构体来组织相关的变量,以便管理和操作这些串口。以下是一个示例,定义了一个结构体来表示三个串口的相关变量:

typedef struct {
    // 串口0相关变量
    volatile uint8_t uart0_rx_buffer[UART_RX_BUFFER_SIZE];
    volatile uint8_t uart0_tx_buffer[UART_TX_BUFFER_SIZE];
    volatile uint8_t uart0_rx_index;
    volatile uint8_t uart0_tx_index;
    volatile bool uart0_rx_complete;

    // 串口1相关变量
    volatile uint8_t uart1_rx_buffer[UART_RX_BUFFER_SIZE];
    volatile uint8_t uart1_tx_buffer[UART_TX_BUFFER_SIZE];
    volatile uint8_t uart1_rx_index;
    volatile uint8_t uart1_tx_index;
    volatile bool uart1_rx_complete;

    // 串口2相关变量
    volatile uint8_t uart2_rx_buffer[UART_RX_BUFFER_SIZE];
    volatile uint8_t uart2_tx_buffer[UART_TX_BUFFER_SIZE];
    volatile uint8_t uart2_rx_index;
    volatile uint8_t uart2_tx_index;
    volatile bool uart2_rx_complete;
} SerialPorts;

// 定义一个实例化的结构体变量
SerialPorts serial_ports;

结构体成员说明:

  • uartX_rx_buffer: 串口X接收缓冲区,用于存储从串口X接收到的数据。
  • uartX_tx_buffer: 串口X发送缓冲区,用于存储待发送至串口X的数据。
  • uartX_rx_index: 串口X接收缓冲区的索引,指示下一个接收数据的位置。
  • uartX_tx_index: 串口X发送缓冲区的索引,指示下一个发送数据的位置。
  • uartX_rx_complete: 串口X接收完成标志,用于指示是否完成了一次数据接收。

注意事项:

  1. volatile 关键字

    • 在单片机编程中,通常使用 volatile 关键字来声明这些变量,以确保编译器不会对它们进行优化,保证每次访问都是直接从内存中读取或写入。
  2. 缓冲区大小定义

    • UART_RX_BUFFER_SIZEUART_TX_BUFFER_SIZE 是根据实际需求定义的宏或常量,表示串口接收和发送缓冲区的大小。
  3. 多个串口的区分

    • 结构体中通过命名方式区分不同的串口变量,如 uart0_...uart1_...uart2_...

通过这种方式,你可以方便地管理和操作多个串口的数据收发,使代码结构更清晰,易于维护和扩展。