开发编码规范笔记

news2024/9/19 11:00:50

前言

(1)该博客仅用于个人笔记

格式转换

(1)查看是 LF 行尾还是CRLF 行尾。

# 单个文件,\n 表示 LF 行尾。\r\n 表示 CRLF 行尾。
hexdump -c <yourfile>
# 单个文件,'$' 表示 LF 行尾。'^M$' 表示 CRLF 行尾。
cat -e <yourfile>

(2)将文件转换为LF格式。

# 单个文件
dos2unix <yourfile>
# 批量操作
find <path> -type f -exec dos2unix {} \;

(3)将文件转换为CRLF格式。

# 单个文件
unix2dos <yourfile>
# 批量操作
find <path> -type f -exec unix2dos {} \;

C代码规范

断言

适用场景

(1)assert() 只能用于检测由于严重的内部逻辑错误或损坏而导致程序无法继续运行的不可恢复的错误。对于可恢复的错误,包括由于无效的外部输入而可能出现的错对于误,应返回错误值。
(2)对于返回值为esp_err_t类型的函数,应该使用ESP_ERROR_CHECK()而不是assert()

断言设置使能

(1)对于断言的设置,可以进入 menuconfig 搜索 CONFIG_COMPILER_OPTIMIZATION_ASSERTION_LEVEL 进行配置:

  • Enabled : 启动断言功能。当断言失败时,会打印出断言的内容和行号。适用于开发阶段,因为它可以帮助开发者快速定位和修复代码中的错误。
  • Silent : 启动静默。断言失败时,不会打印出具体的断言信息和行号,而是直接中止程序。开发者需要通过中止地址来查找断言失败的位置。适用于在某些情况下需要节省代码大小的场景,同时仍然希望保留某种程度的断言检查
  • Disabled : 禁用断言。禁用断言后,任何断言检查都不会执行,从而提高程序的性能。

在这里插入图片描述

“变量设置但未使用”警告

(1)如果断言被失能,那么下面的 res 可能会出现“变量设置但未使用”警告。

int res = do_something();
assert(res == 0);

(2)为了避免这样的问题,我们可以让所有的返回值用同一个变量定义,然后加上关键字即可。

int res __attribute__((unused));

res = do_something();
assert(res == 0);

res = do_something_else();
assert(res != 0);

变量

前缀

(1)静态全局变量用 g_ 前缀,静态局部变量用 s_ 前缀。作用域仅限于当前文件的变量必须声明为静态变量 static

static uint8_t g_num; // 静态全局变量用 g_ 前缀
int main()
{
	static uint8_t s_num; // 静态局部变量用 s_ 前缀
	while (1);
}

使用

(2)变量注意重入问题。 尽量在一个固定函数中操作静态全局变量。使用 get_ set_ 等接口进行变量操作。

static SemaphoreHandle_t g_mutexhandle = NULL;  // 变量定义要赋初值,全局静态变量以 g_ 前缀
static uint8_t g_num = 0;                       // 变量定义要赋初值,全局静态变量以 g_ 前缀

static void set_num(uint8_t value) // 使用 set_ 前缀接口操作变量
{
	// 获得信号量
	xSemaphoreTake(g_mutexhandle, portMAX_DELAY);
	g_num = value;
	// 释放信号量
	pthread_mutex_unlock(g_mutexhandle);
}

static int get_num() // 使用 get_ 前缀接口操作变量
{
	uint8_t value;
	// 获得信号量
	xSemaphoreTake(g_mutexhandle, portMAX_DELAY);
	value = g_num;
	// 释放信号量
	pthread_mutex_unlock(g_mutexhandle);
	return value;
}

int main() 
{
	static uint8_t s_count; // 静态局部变量用 s_ 前缀
	// 创造互斥量
	g_mutexhandle = xSemaphoreCreateMutex();
	while(1){
		set_num(10);
		s_count = get_num(); // 静态全局变量用 g_ 前缀
	    vTaskDelay(pdMS_TO_TICKS(1000));
    }
    vSemaphoreDelete(g_mutexhandle);
    g_mutexhandle = NULL; // 句柄类型变量,在对象销毁后,应重新赋值为 NULL
}

变量名

(1)变量应尽量使用有意义的词语,或者已经达成共识的符号或变量缩写

在这里插入图片描述

函数

(1)如果一个函数存在重入和线程安全问题,需在注释中说明。

/**
 * @brief 打印函数,该函数存在线程安全问题
 * 
 * @param __restrict 字符串
 * @param ...        可变参数
 * @return int 
 */
int	printf (const char *__restrict, ...);

(2)函数名统一使用小写,同一组件保持同一前缀。

在这里插入图片描述

头文件

固定格式

(1)头文件固定如下格式。

#ifndef FILE_NAME_H /* 名字要与 .c 文件对应 */
#define FILE_NAME_H

#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */

/********************************************
 *               头文件内容写里面
 ********************************************/

#ifdef __cplusplus
}
#endif /* __cplusplus */

#endif /* FILE_NAME_H */

类型定义

(1)类型都需要通过 typedef 定义并且命名

typedef enum{
    MODULE_FOO_ONE,
    MODULE_FOO_TWO,
    MODULE_FOO_THREE
} module_foo_t; /* typedef 之后名字后缀为 _t */

typedef struct {
    esp_chip_model_t model;  
    uint32_t features;       
    uint16_t revision;      
    uint8_t cores;          
} esp_chip_info_t; /* typedef 之后名字后缀为 _t */

格式化代码

(1)如果重头写一个文件,可以使用 astyle 工具。

# 格式化代码
astyle example.c
# 使用乐鑫官方脚本
${esp-idf}/tools/format.sh <yourfile>

最终代码演示

C代码

/*********************************************************************************
 *                                 版权声明
 *********************************************************************************/
/*
 * SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD
 *
 * SPDX-License-Identifier: Apache-2.0
 */


/*********************************************************************************
 *                                 头文件规范
 *********************************************************************************/
// #include < C 标准库头文件           >
// #include < POSIX 头文件及其常见扩展  >
// #include " IDF 头文件              "
// #include " 组件头文件,例如 FreeRTOS "
// #include " 私有头文件               "

#define uint8_t unsigned char
#define NULL 0
#define portMAX_DELAY -1

/*********************************************************************************
 *                                变量定义规范
 *********************************************************************************/
static uint8_t g_num = 5, g_x = 0, g_y = 0; /* ","仅后面有空格,静态全局变量用 g_ 前缀  */
static uint8_t *g_z = NULL;
static SemaphoreHandle_t g_mutexhandle = NULL;      // 互斥量

/*********************************************************************************
 *                                 代码规范
 *********************************************************************************/
static void circulate_function()
{/* 函数定义的括号应该单独一行 */
    if (g_num) { /* 循环关键字后面加一个空格,函数内左括号与条件放在同一行 */
        printf("hello");
    }else if (g_x) {
        printf("world");
    }
    for (; g_x < g_num; g_x++) { /* 循环关键字后面加一个空格,函数内左括号与循环放在同一行 */
        printf("esp");
    }
    while (g_x){ /* 循环关键字后面加一个空格,函数内左括号与循环放在同一行 */
        printf("esp32");
    }
    switch (g_num) { /* 循环关键字后面加一个空格,函数内左括号与循环放在同一行 */ 
    case 0:
        break;
    
    default:
        break;
    } 
}

/* 尽量在一个固定函数中操作静态全局变量 */
static void set_num(uint8_t value) // 使用 set_ 前缀接口操作变量
{
	// 获得信号量
	xSemaphoreTake(g_mutexhandle, portMAX_DELAY);
	g_num = value;
	// 释放信号量
	pthread_mutex_unlock(g_mutexhandle);
}

static int get_num() // 使用 get_ 前缀接口操作变量
{
	uint8_t value;
	// 获得信号量
	xSemaphoreTake(g_mutexhandle, portMAX_DELAY);
	value = g_num;
	// 释放信号量
	pthread_mutex_unlock(g_mutexhandle);
	return value;
}

int main() /* 函数之间放置一个空行 */
{
    /* Tab 键为4个空格,而不是制表符进行缩进 */
    /* 如果不需要这行代码,直接删除,否则就解释禁用原因。 */
    // printf("hello world");

	static uint8_t s_count; // 静态局部变量用 s_ 前缀
	// 创造互斥量
	g_mutexhandle = xSemaphoreCreateMutex();
	while(1){
		set_num(10);
		s_count = get_num();  // 因为该变量不存在重入问题,因此不需要进行保护
	    vTaskDelay(pdMS_TO_TICKS(1000));
    }
    vSemaphoreDelete(g_mutexhandle);
    g_mutexhandle = NULL; // 句柄类型变量,在对象销毁后,应重新赋值为 NULL

    // 获得信号量
    xSemaphoreTake(g_mutexhandle, portMAX_DELAY);

    /* 一元运算符不需要空格 */
    g_x = g_num++; 
    g_y = g_num--; 
    *g_z = &g_num; 
    g_x = !g_num; 
    g_x = ~g_x;
    g_y = *g_z;
    g_x = (uint8_t)g_x;

    /* 二元运算符需要空格 */
    g_num = g_x + g_y;
    g_num = g_x - g_y;
    g_num = g_x * g_y; /* 这个可以删除空格 */
    g_num = g_x*g_y; 
    g_num = g_x / g_y; /* 这个可以删除空格 */
    g_num = g_x/g_y;
    g_num = g_x % g_y;
    g_num = (g_x == g_y);
    g_num = (g_x != g_y);      
    g_num = (g_x > g_y);       
    g_num = (g_x < g_y);       
    g_num = (g_x >= g_y);      
    g_num = (g_x <= g_y);      
    g_num = (g_x && g_y);  
    g_num = (g_x || g_y); 
    g_num = g_x & g_y;  
    g_num = g_x | g_y;      
    g_num = g_x ^ g_y;      
    g_num = g_x << 1;     
    g_num = g_x >> 1;     
    g_x += 3;  
    g_x -= 2;  
    g_x *= 2;  
    g_x /= 4;  
    g_x %= 2;  
    g_y &= 3;   
    g_y |= 2;   
    g_y ^= 3;   
    g_y <<= 1;  
    g_y >>= 1;  

    // 释放信号量
    pthread_mutex_unlock(g_mutexhandle);
}

头文件

#ifndef FILE_NAME_H /* 名字要与 .c 文件对应 */
#define FILE_NAME_H

#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */

/* 枚举要通过 typedef 定义并且命名 */
typedef enum {
    MODULE_FOO_ONE,
    MODULE_FOO_TWO,
    MODULE_FOO_THREE
} module_foo_t; /* typedef 之后名字后缀为 _t */


/**
 * @brief 该函数存在线程安全问题
 * 
 * @param __restrict 
 * @param ... 
 * @return int 
 */
int	printf (const char *__restrict, ...);

#ifdef __cplusplus
}
#endif /* __cplusplus */

#endif /* FILE_NAME_H */

参考

(1)Espressif IoT Development Framework Style Guide

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1918961.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

晨持绪电商:开一家抖音网店到底有前景吗

在数字化浪潮汹涌的今天&#xff0c;抖音作为一颗耀眼的新星&#xff0c;不仅重塑了人们的娱乐方式&#xff0c;更是成为电商领域的新战场。但许多人仍在观望&#xff0c;心中充满疑问&#xff1a;开一家抖音网店&#xff0c;究竟有没有前景? 抖音的流量优势不容忽视。凭借数亿…

CVE-2024-23692: Rejetto HTTP File Server 2.3m Unauthenticated RCE漏洞复现

目录 本文章仅供学习使用&#xff01;&#xff01;&#xff01; Rejetto HTTP介绍 漏洞简介 漏洞环境 漏洞复现 exp 复现 结果 如何修复 本文章仅供学习使用&#xff01;&#xff01;&#xff01; Rejetto HTTP介绍 Rejetto是一个流行的开源软件项目&#xff0c;主要…

【RHCE】dns实验0709

题目&#xff1a; 配置主服务器的web内容 web部分 创建web页面 修改增加etc/hosts内容且重启 测试&#xff1b; dns 区域文件 防火墙放行&#xff1a; 主服务器测试从服务器 从服务器 web dns 防火墙放行服务 selinux放行&#xff1a; 创建文件 定义特定文件 测试&#xff1…

ROS基础学习-ROS运行管理

ROS运行管理 目录 1. ROS运行管理简述2. ROS元功能包2.1 概念2.2 作用2.3 实现 3. ROS-launch文件3.1. ROS节点管理launch文件3.1.1 概念3.1.2 作用3.1.3 使用 3.2 launch文件标签 1. ROS运行管理简述 ROS是多进程(节点)的分布式框架&#xff0c;一个完整的ROS系统实现&#x…

城市窨井盖监测设备:让城市井盖不再“蹦迪”

近日&#xff0c;郑州暴雨来袭&#xff0c;街道瞬间变成河流&#xff0c;而原本默默无闻的井盖却成了“网红”&#xff0c;由于暴雨强大的水流压力&#xff0c;使它们在水中“随波逐流”上下跳动&#xff0c;网友直呼&#xff1a;这年头井盖都会“蹦迪”了。虽然是一句调侃&…

教你怎么不开DLSS3.0也能有效提高永劫无间帧数

永劫无间&#xff0c;一款国风的多人对战竞技游戏&#xff0c;游戏画面特别精美&#xff0c;在游戏中给玩家强烈的打击感&#xff0c;玩家在游玩过程中仿佛置身于游戏&#xff0c;而且此游戏非常受玩家欢迎。游戏中可以进行三人、双人、单人进行游玩&#xff0c;我们需要选择出…

前端必修技能:高手进阶核心知识分享 - 三万字详解CSS动画效果

在CSS的世界里,存在着多种能体现动画效果的属性:CSS transform、CSS Transition 和 CSS Animation。让开始接触CSS的同学感到困惑。要搞清楚CSS的动画,我们就必须先把这几种属性做一下区别。 CSS transform 属性、CSS Transition 属性、 CSS Animation 属性的区别 CSS tra…

地理信息科学在灾害管理中的应用:GIS构建防灾减灾的智慧防线

在全球气候变化与人类活动加剧的背景下&#xff0c;自然灾害频发&#xff0c;给社会经济发展带来了严峻挑战。本文将深入分析GIS在灾害预测、评估和响应中的核心作用&#xff0c;展示其如何为构建更加安全、韧性的社会提供智慧解决方案。 灾害预测&#xff1a;GIS的“先知”之…

【学习css2】grid布局-页面footer部分保持在网页底部

中间内容高度不够屏幕高度撑不开的页面时候&#xff0c;页面footer部分都能保持在网页页脚&#xff08;最底部&#xff09;的方法 1、首先上图看显示效果 2、奉上源码 2.1、html部分 <body><header>头部</header><main>主区域</main><foot…

YOLOv8改进 | 注意力机制| 对小目标友好的BiFormer【CVPR2023】

秋招面试专栏推荐 &#xff1a;深度学习算法工程师面试问题总结【百面算法工程师】——点击即可跳转 &#x1f4a1;&#x1f4a1;&#x1f4a1;本专栏所有程序均经过测试&#xff0c;可成功执行&#x1f4a1;&#x1f4a1;&#x1f4a1; 专栏目录 &#xff1a;《YOLOv8改进有效…

前端一面之 同步 vs 异步

异步 vs 同步 先看一下 下面的 demo console.log(100) setTimeout(function () {console.log(200) }, 1000) console.log(300) 执行结果 100 300 200console.log(100) alert(200) // 1秒钟之后点击确认 console.log(300) 这俩到底有何区别&#xff1f;—— 第一个示例中间的…

5,智能合约(react+区块链实战)

5&#xff0c;智能合约&#xff08;react区块链实战&#xff09; 5-1 智能合约5-2 metamask安装及私有链搭建互相联动5-3 solidity数据类型-布尔-数字-地址&#xff08;owner区别&#xff09;5-4 solidity 数组和映射&#xff08;代币转账&#xff09;5-5 solidity结构体与枚举…

强制升级最新系统,微软全面淘汰Win10和部分11用户

说出来可能不信&#xff0c;距离 Windows 11 正式发布已过去整整三年时间&#xff0c;按理说现在怎么也得人均 Win 11 水平了吧&#xff1f; 然而事实却是&#xff0c;三年时间过去 Win 11 占有率仅仅突破到 29%&#xff0c;也就跳起来摸 Win 10 屁股的程度。 2024 年 6 月 Wi…

【测试文档】系统测试报告(Word原件2024)

软件测试报告在软件开发过程中起着至关重要的作用&#xff0c;主要有以下几个主要原因&#xff1a; 1、确保软件质量 2、提供决策支持 3、记录测试过程和结果 4、促进沟通和协作 5、符合标准和法规要求 6、改进测试流程和策略 7、降低风险 软件开发全套资料获取进主页或者本文末…

【redis缓存】怎么使用 Redis 实现一个延时队列?

redis实现延时队列 1 回答2 代码实现2.1 利用 Redis 过期消息实现延时队列2.1.1 配置键空间通知2.1.2 应用程序订阅过期事件 2.2 使用 Sorted Set 实现延时队列2.2.1 实现思路2.2.2 详细步骤 2.3 Redisson 实现延迟队列2.3.1 添加Redisson依赖2.3.2 任务生产者类 TaskProducer2…

一文入门【NestJs】Providers

Nest学习系列 ✈️一文入门【NestJS】 ✈️一文入门【NestJs】Controllers 控制器 &#x1f6a9; 前言 在NestJS的世界里&#xff0c;理解“Providers”是构建健壮、可维护的后端服务的关键。NestJS&#xff0c;作为Node.js的一个现代框架&#xff0c;采用了Angular的一些核…

轻松搭建系统,让每个故事都精彩绽放!

"轻松搭建系统&#xff0c;让每个故事都精彩绽放&#xff01;" 这句话传递了一个核心理念&#xff0c;即通过简化、高效的系统搭建过程&#xff0c;让每一个创意故事都能以最佳状态呈现给观众&#xff0c;实现其独特魅力和价值的最大化。 1、模块化设计&#xff1a;系…

Docker初识及使用研究

公司使用docker&#xff0c;小组成员人人都是默默使用&#xff0c;也没讲解培训&#xff0c;真是搞笑。 目录 1. Docker安装 1. Docker安装 需要使用梯子访问docker官网&#xff1a;Install Docker Engine on Ubuntu 此处有个疑惑&#xff1a;Docker Engine 与Docker、Docker…

排序(一)——冒泡排序、直接插入排序、希尔排序(BubbleSOrt,InsertSort,ShellSort)

欢迎来到繁星的CSDN&#xff0c;本期的内容主要包括冒泡排序(BubbleSort&#xff09;&#xff0c;直接插入排序(InsertSort)&#xff0c;以及插入排序进阶版希尔排序&#xff08;ShellSort&#xff09;。 废话不多说&#xff0c;直接上正题&#xff01; 一、冒泡排序 冒泡排序…

国漫推荐04

童年经典 1.《喜羊羊与灰太狼》 2.《虹猫蓝兔七侠传》 3.《虹猫蓝兔走天涯》 4.《虹猫蓝兔光明剑》 5.《蓝猫龙骑团》 6.《爆丸小子》 7.《超智能足球》 8.《摩尔庄园》 9.《赛尔号》 10.《恐龙宝贝》 11.《天上掉下个猪八戒》 12.《天眼》