当前位置: 首页 > news >正文

C/C++ 代码规范、编程思想与常用代码块

@

目录
  • 1. 代码规范
    • 1.1 排版格式
      • 1.1.1 Tab
      • 1.1.2 swich - case
      • 1.1.3 一行只写一条语句
      • 1.1.4 括号的起止应独立占用一行
      • 1.1.5 空格
      • 1.1.6 空行
      • 1.1.7 括号
    • 1.2 注释
      • 1.2.1 多行注释
      • 1.2.2 函数说明
      • 1.2.3 代码块说明
    • 1.3 变量、函数等规范
      • 1.3.1 代码管理
        • 1.3.1.1 README.txt文档
        • 1.3.1.2 UpdateLog.txt文档
      • 1.3.2 使用assert()判断输入变量
      • 1.3.3 复杂参数使用结构体进行参数传递
    • 1.4 命名法
      • 1.4.2 变量命名法
      • 1.4.3 使用枚举、宏定义代替数字
      • 1.4.4 常用命名缩写
  • 2. 编程思想
    • 2.1 高内聚,低耦合
    • 2.2 DRY原则 (Don't Repeat Yourself)
    • 2.3 重构 (Refactoring)
  • 3. 常用功能代码块
    • 3.1 提取字符串并转换为浮点数及其相关处理
    • 3.2 提取字符串并及其相关处理
    • 3.3 提取字符串并转换为整数及其相关处理

1. 代码规范


1.1 排版格式


1.1.1 Tab

设置每按一次Tab键,代码缩进4个空格。

1.1.2 swich - case

  1. swich - case必须要完整,必须包含最后的default语句。
  2. swichcase标签应该对齐处于同一列。
switch (suffix) 
{case 'G':case 'g':mem <<= 30;break;case 'M':case 'm':mem <<= 20;break;case 'K':case 'k':mem <<= 10;/* fall through */default:break;
}
  1. 对于 switch 语句下的 case 语句,如果因为特殊情况需要处理完一个 case 后进入下一个 case 处理,必须在该 case 语句处理完、下一个 case 语句前加上明确的注释。
switch (suffix) 
{case 'G':// 跳转到 'g'case 'g':mem <<= 30;break;case 'M':// 跳转到 'm'case 'm':mem <<= 20;break;case 'K':// 跳转到 'k'case 'k':mem <<= 10;break;default:break;
}

1.1.3 一行只写一条语句

//不规范的写法: 
a = x+y; b = x-y;
//规范的写法
a=x+y;
b=x-y;

1.1.4 括号的起止应独立占用一行

if (x is true)
{we do y
}int function(int x)
{body of function
}

1.1.5 空格

  1. 在以下关键字后添加一个空格:if、swich、case、for、do、while.
  2. 不要在 sizeof、typedof、alignof 或者__attribute__这些关键字/运算符后面添加空格。
  3. 二元或者三元操作符两侧都要加一个空格。= + - < > * / % | & ^ <= >= == != ? :
  4. 一元操作符后不要加空格。& * + - ~ ! sizeof typeof alignof __attribute__ defined
  5. 后缀自加或者自减的一元操作符前后都不加空格。++ --
  6. .->这两个结构体成员操作符前后不加空格。
  7. 逗号、分号只在后面添加空格。int a, b, c;
  8. 注释符/*/与注释内容之间要添加一个空格。

1.1.6 空行

  1. 相对独立的程序块之间、变量说明之后必须加空行。
void DemoFunc(void){uint8_t i;//<---- 局部变量和语句间空一行/* 功能块 1 */for (i = 0; i < 10; i++){...}//<---- 不同的功能块间空一行/* 功能块 2 */for (i = 0; i < 20; i++){...}}

1.1.7 括号

注意运算符的优先级,并用括号明确表达式的操作顺序,应避免使用默认优先级。

注:防止阅读程序时产生误解,防止因默认的优先级与设计思想不符而导致程序出错。

word = (high << 8) | low;
if ((a | b) && (a & c))
if ((a | b) < (c & d))

1.2 注释


1.2.1 多行注释

注释头、尾使用80个*号。

/********************************************************************************
This is the preferred style for multi-line
comments in the Linux kernel source code.
Please use it consistently.Description: A column of asterisks on the left side,
with beginning and ending almost-blank lines.
********************************************************************************/

1.2.2 函数说明

/*** @brief Briefly describe the main purpose of the function.* * Provide a more detailed description here if necessary. Explain the logic, * the algorithm used, or the specific business rules this function implements.* * @param paramName1 Description of the first parameter (e.g., input data, user ID).* @param paramName2 Description of the second parameter (e.g., timeout in milliseconds).* @return Description of the return value (e.g., returns true on success, false otherwise).* @note Important notes, such as thread safety, memory management responsibilities, *       or specific environment requirements.* @warning Potential risks or side effects (e.g., this function modifies the global state).*/

1.2.3 代码块说明

位于函数内部的功能代码块,可用以下注释说明与高亮

/*	xxx CODE BLOCK START	*/...
/*	xxx CODE BLOCK END	*/

1.3 变量、函数等规范

  1. 一个函数只能完成一个功能。
  2. 一个变量只能有一个功能。
  3. 宏定义、枚举标签使用全大写。如:#define CONSTANT 0x12345

1.3.1 代码管理

1.3.1.1 README.txt文档

每个代码工程都应该包含一个README.txt的文档以说明代码的功能和用法。

/*************************************************
* Project name: 
* Author: 
* Description: 用于详细说明此程序文件完成的主要功能,与其他模块或函数的接口,输出值、取值范围、含义及参数间的控制、顺序、独立或依赖等关系
* Others:  其它内容的说明
*************************************************/

1.3.1.2 UpdateLog.txt文档

每个代码工程都应该包含一个UpdateLog.txt的文档以记录每次修改代码的记录,参考模板如下:

/************************************************************************************/
更新时间:
更新人:
更新后版本号:
更新内容:1.  2. 3. 
/************************************************************************************/

1.3.2 使用assert()判断输入变量

如果约定由调用方检查参数输入,则应使用assert()之类的宏,来验证所有参数输入的有效性。

关于assert()的用法,详见C理论之二——运算符、三大结构、文件操作

1.3.3 复杂参数使用结构体进行参数传递

为了减少函数间接口的复杂度,复杂的参数或输入参数过多时可以使用结构传递。

1.4 命名法

1.4.2 变量命名法

  1. 变量、函数命名使用小驼峰命名法或蛇形命名法,命名尽量不使用英文缩写、建议使用全拼英文(行业通用名除外),不准使用拼音缩写和拼音拼写。如:getUserInfoget_user_info
  2. 变量命名前缀增加分类标识,如Flag 变量就应在变量前或后加flagFlag
  3. 单个字符命名的变量ijk仅建议在局部变量中使用。

1.4.3 使用枚举、宏定义代替数字

避免使用不易理解的数字,用有意义的标识来替代。涉及物理状态或者含有物理意义的常量,不应直接使用数字,必须用有意义的枚举或宏来代替。

enum trunk_state_e{TRUNK_IDLE = 0,TRUNK_BUSY = 1
};if (Trunk[index].trunk_state == TRUNK_IDLE) // 不建议直接使用Trunk[index].trunk_state == 0{Trunk[index].trunk_state = TRUNK_BUSY;... /* program code */
}

1.4.4 常用命名缩写

	/*argument 可缩写为 argbuffer 可缩写为 buffclock 可缩写为 clkcommand 可缩写为 cmdcompare 可缩写为 cmpconfiguration 可缩写为 cfgdevice 可缩写为 deverror 可缩写为 errhexadecimal 可缩写为 hexincrement 可缩写为 incinitialize 可缩写为 initmaximum 可缩写为 maxmessage 可缩写为 msgminimum 可缩写为 minparameter 可缩写为 paraprevious 可缩写为 prevregister 可缩写为 regsemaphore 可缩写为 semstatistic 可缩写为 statsynchronize 可缩写为 synctemp 可缩写为 tmp
*/

2. 编程思想

2.1 高内聚,低耦合

  • 高内聚:模块(比如一个类、一个函数)内部各司其职,每个模块专注于做好一件事;
  • 低耦合:模块之间要相互独立,减少相互依赖和干扰;

2.2 DRY原则 (Don't Repeat Yourself)

如果一段代码逻辑在多个地方出现,应该将其提取成一个公共的函数或组件,避免代码冗余带来的维护噩梦;

2.3 重构 (Refactoring)

在不改变代码外部行为的前提下,对代码内部结构进行调整和优化。目的是消除代码异味(如重复代码、过长函数),提高代码的可读性和可维护性。

3. 常用功能代码块


3.1 提取字符串并转换为浮点数及其相关处理

/*** 从格式化字符串中提取浮点数值,存储到EEPROM并记录日志* * @param prefixStr      基准前缀字符串,用于定位数据起始位置* @param inputStr       包含[前缀][浮点数据]格式的输入字符串,即输入的字符串* @param eepromAddr     EEPROM中存储浮点数的目标地址* @param formatStr      用于打印输出和日志记录的格式化字符串* @param floatValue     存储解析后浮点数的指针* @param comType        通信类型参数(串口或网口)* @return               成功返回SUCCESS(0),失败返回错误码*/
uint8_t Set_fdata(const char *prefixStr,     char *inputStr,            uint16_t eepromAddr,       const char *formatStr,     float *floatValue,         uint8_t comType           
)
{// 计算字符串长度uint8_t len=strlen(prefixStr);uint8_t leng=strlen(inputStr);uint8_t i = 0;char sss[8]; // 创建一个 8 字节的缓冲区sss存储提取的浮点数字符串char *p=&inputStr[len]; // 指针p指向inputStr中前缀后的第一个字符char log_data[100];// 从p开始复制最多 8 个字符到sssfor(i=0;((i<leng - len)&&i<8);i++) {if(p[i] != '\0')sss[i]=p[i];}sss[i]='\0'; // 添加字符串终止符\0*floatValue = atof(sss); // 使用atof函数将提取的字符串转换为浮点数AT24CXX_Write_Float(BROM_DEVICE_ADDR,eepromAddr,(uint8_t *)floatValue,EEPROM_IIC); // 将浮点数写入指定的 EEPROM 地址Board_Printf(comType,formatStr,*floatValue);sprintf(log_data,formatStr,*floatValue);Write_fixture_log(log_data,log_fixture_set_path,comType);return 0;
}

例程:

char *ptr ="";
const char  *str1 ="Set Fixture Temp offset:"; // 基准前缀字符串
const char  *str1_1 ="Set Fixture Temp offset:%.4f Pass\r\n@_@"; // 用于打印输出和日志记录的格式化字符串float temp_offset = 0;									// 温度校验Offset#define TEMP_OFFSET_ADDR			3055				// 校验温度 Offset储存地址
#define COM_UART4       			4					// 串口4			
uint8_t com_type = COM_UART4;Set_fdata(str1,ptr,FIXTURE_TMP_OFFSET_ADDR,str1_1,&fixture_tmp_offset,com_type);
- 输入:从串口4输入信息:Set Fixture Temp offset: 2.2- 输出:Set Fixture Temp offset:2.2 Pass- 并内部将浮点数2.2存入到地址为`TEMP_OFFSET_ADDR` 的EEPROM 地址中

3.2 提取字符串并及其相关处理

/*
从一个包含特定前缀的字符串中提取目标数据,将其存储到 EEPROM 中
*/
void Set_string(const char *prefixStr,     // 基准前缀字符串,用于定位数据起始char *inputStr,            // 包含[前缀][数据]格式的完整输入字符串,即输入的字符串uint16_t eepromAddr,       // EEPROM中存储字符串的起始地址const char *formatStr,     // 用于打印和日志的格式化字符串char *outputStr,           // 存储提取数据的输出缓冲区uint8_t comType           // 通信类型参数(传递给打印和日志函数)
)
{// 计算字符串长度uint8_t len=strlen(prefixStr);uint8_t leng=strlen(inputStr);uint8_t i = 0;uint8_t ii = 0;char *p=&inputStr[len]; // 指向输入字符串中前缀后的位置char log_data[100];// 从前缀后的位置开始,复制数据到输出缓冲区 outputStr,直到输入字符串结束for(i=0;i<leng - len;i++){if(p[i] != '\0')outputStr[i]=p[i];}outputStr[i]='\0';// 添加字符串结束符// 将提取的数据逐个字节写入 EEPROM,包括字符串结束符 '\0'for(ii=0;ii<i+1;ii++){AT24CXX_WriteOneByte(BROM_DEVICE_ADDR,eepromAddr+ii,outputStr[ii],EEPROM_IIC);}// 通过指定通信接口输出结果,并记录操作日志。Board_Printf(comType,formatStr,outputStr);sprintf(log_data,formatStr,outputStr);Write_fixture_log(log_data,log_fixture_set_path,comType);return;
}

例程:

char *ptr ="";
const char  *str1 ="Set Fixture Number "; // 基准前缀字符串
const char  *str1_1 ="Set Fixture Number %s Pass\r\n@_@"; // 用于打印输出和日志记录的格式化字符串#define SN_ADDR						5				// EEPROM 储存地址
#define COM_UART4       			4					// 串口4	uint8_t com_type = COM_UART4;
char fixtureSN[6]; // 缓存变量Set_string(str1,ptr,SN_ADDR,str1_1,fixtureSN,com_type);
- 输入:从串口4输入信息:Set Fixture Number: 001- 输出:Set Fixture Number 001 Pass- 并内部将字符串001存入到地址为`SN_ADDR` 的EEPROM 地址中

3.3 提取字符串并转换为整数及其相关处理

uint8_t Set_data(const char *prefixStr,     // 基准前缀字符串,用于定位数据起始char *inputStr,            // 包含[前缀][数据]格式的完整输入字符串,即输入的字符串uint16_t eepromAddr,       // EEPROM中存储整数的目标地址const char *formatStr,     // 用于打印和日志的格式化字符串uint16_t *valuePtr,        // 存储解析后整数值的指针uint16_t maxValue,         // 数值上限检查阈值uint8_t comType           // 通信类型参数(传递给打印和日志函数)
)
{uint8_t len=strlen(prefixStr);uint8_t leng=strlen(inputStr);uint8_t i = 0;char sss[7];char *p=&inputStr[len];char log_data[100];for(i=0;i<leng - len;i++){if(p[i] != '\0')sss[i]=p[i];}sss[i]='\0';*valuePtr = atoi(sss);if(*valuePtr > maxValue)						//{Board_Printf(comType,inputStr);Board_Printf(comType," fail\r\n@_@");*valuePtr = AT24CXX_ReadLenByte(BROM_DEVICE_ADDR,eepromAddr,4,EEPROM_IIC);return 1;}AT24CXX_WriteLenByte(BROM_DEVICE_ADDR,eepromAddr,*valuePtr,4,EEPROM_IIC);Board_Printf(comType,formatStr,*valuePtr);sprintf(log_data,formatStr,*valuePtr);Write_fixture_log(log_data,log_fixture_set_path,comType);return 0;
}

例程:

char *ptr ="";
const char  *str1 ="Set Network PORT:"; // 基准前缀字符串
const char  *str1_1 ="Set Network PORT:%d Pass\r\n@_@"; // 用于打印输出和日志记录的格式化字符串
uint16_t SERVER_PORT = 5000;										// tcp服务器监听端口号#define NET_PORT_ADDR				4050				// EEPROM 储存地址
#define COM_UART4       			4					// 串口4	uint8_t com_type = COM_UART4;
char fixtureSN[6]; // 缓存变量Set_string(str1,ptr,SN_ADDR,str1_1,fixtureSN,com_type);
- 输入:从串口4输入信息:Set Fixture Number: 001- 输出:Set Fixture Number 001 Pass- 并内部将字符串001存入到地址为`SN_ADDR` 的EEPROM 地址中
http://www.jsqmd.com/news/847420/

相关文章:

  • 在RV1126开发板上搞定SIMCOM A7670C 4G模块:从内核驱动到AT指令上网全流程
  • OpenClaw用户配置Taotoken作为后端AI供应商的详细步骤
  • 用STM32和HC-SR04做个智能小车避障,代码和接线图都给你准备好了
  • 实地探访!绍兴在职学历提升机构怎么选? 口碑推荐与避坑指南 - 奔跑123
  • R40B网关在充电桩运维中的实战应用:从数据采集到智能告警
  • C++17 std::variant避坑指南:从std::monostate到valueless_by_exception,这些细节你注意了吗?
  • 2026苏州装修公司排行,专业实力深度测评推荐榜 - 资讯速览
  • 三星固件下载终极指南:Bifrost跨平台工具完整使用手册
  • 【亲测门店】新昌吊车企业对比,哪家更靠谱?新昌吊车联系方式 - 花开富贵112
  • 泡沫包装厂家怎么选?这3点帮你避坑 - 资讯速览
  • 2026年平价中医教学设备选型分析报告:高性价比产品推荐与场景适配解读 - 温茶叙旧
  • 绍兴GEO服务商怎么选才靠谱? - 资讯速览
  • G-Helper完全解析:重新定义华硕笔记本性能控制的终极指南
  • 5分钟快速上手causal-conv1d:CUDA加速的因果卷积库
  • 你的微信聊天记录,真的安全吗?揭秘永久保存数字记忆的开源方案
  • Erlang 版本不匹配导致 RabbitMQ 启动失败怎么处理
  • wpa_ctrl接口简介和使用总结
  • 主流原型设计工具--墨刀介绍
  • 2026年中医四诊教学设备市场选型指南:核心标准与主流产品解析 - 温茶叙旧
  • 国产RISC-V核心板FET7110-C开发实战:从JH7110 SoC到Qt应用部署
  • 【软考高级架构】案例题考前突击——分布式一致性在互联网金融平台的应用
  • 鼎讯 SZT-1000A:交通网络多合一智能测试仪
  • 提高效率
  • 嵌入式ADC性能评估:CDBCAPTURE系统改造与实战调试指南
  • 如何快速解密RPG Maker加密存档:终极免费工具完全指南
  • 嵌入式操作系统选型实战指南:从硬件约束到商业考量的五维决策框架
  • 3步掌握Open-Lyrics:如何让AI为你的音频自动生成专业字幕
  • 别再硬凑尺寸了!用单位增益负反馈搞定二级运放第二级饱和难题
  • 从无人机炸机到平稳飞行:IMU椭球拟合校准实战避坑指南
  • 2026年高端中医教学设备品牌推荐:主流品牌选型参考与核心能力全景分析 - 温茶叙旧