断言和注释规范和编译技巧

断言和注释规范

大纲

  1. 断言
  2. Doxygen 注释规范
  3. 防止头文件包含重复

具体案例

断言

先看示例代码:

void GPIO_Init(GPIO_TypeDef* GPIOx, GPIO_InitTypeDef* GPIO_InitStruct)
 {
 uint32_t pinpos = 0x00, pos = 0x00 , currentpin = 0x00;

 /* Check the parameters */
 assert_param(IS_GPIO_ALL_PERIPH(GPIOx));
 assert_param(IS_GPIO_MODE(GPIO_InitStruct->GPIO_Mode));
 assert_param(IS_GPIO_PIN(GPIO_InitStruct->GPIO_Pin));

 /* ------- 以下内容省略,跟前面我们定义的函数内容相同----- */

基本上每个库函数的开头都会有这样类似的内容,这里的“assert_param”实际是一个宏,在库函数中它用于检查输入参数是否符合要求,若不符合要求则执行某个函数输出警告

“assert_param”的定义

#ifdef USE_FULL_ASSERT
 /**
 * @brief assert_param 宏用于函数的输入参数检查
 * @param expr: 若 expr 值为假,则调用 assert_failed 函数
 * 报告文件名及错误行号
 * 若 expr 值为真,则不执行操作
 */

#define assert_param(expr) ((expr) ? (void)0 : assert_failed((uint8_t *)_
,→_FILE__, __LINE__))
 /* 错误输出函数 ------------------------------------------------------- */
 void assert_failed(uint8_t* file, uint32_t line);
 #else
 #define assert_param(expr) ((void)0)
 #endif

这段代码的意思是,假如我们不定义“USE_FULL_ASSERT”宏,那么“assert_param”就是一个空的宏 (#else 与 #endif 之间的语句生效),没有任何操作。从而所有库函数中的 assert_param 实际
上都无意义,我们就当看不见好了。

假如我们定义了“USE_FULL_ASSERT”宏,那么“assert_param”就是一个有操作的语句 (#if 与#else 之间的语句生效),该宏对参数 expr 使用 C 语言中的问号表达式进行判断,若 expr 值为
真,则无操作 (void 0),若表达式的值为假,则调用“assert_failed”函数,且该函数的输入参数为“FILE”及“LINE”,这两个参数分别代表“assert_param”宏被调用时所在的“文件名”及“行号”。

但库文件只对“assert_failed”写了函数声明,没有写函数定义,实际用时需要用户来定义,我们一般会用 printf 函数来输出这些信息

void assert_failed(uint8_t * file, uint32_t line)
 {
 printf(“\r\n 输入参数错误,错误文件名 =%s, 行号 =%s”,file,line);
}

Doxygen 注释规范

下面还是先一段代码示例

/**
* @brief 初始化控制 LED 的 IO
* @param 无
* @retval 无
*/

这 是 一 种 名 为 “Doxygen” 的 注 释 规 范, 如 果 在 工 程 文 件 中 按 照 这 种 规 范 去 注 释, 可以使用 Doxygen 软件自动根据注释生成帮助文档。我们所说非常重要的库帮助文档《stm32f10x_stdperiph_lib_um.chm》,就是由该软件根据库文件的注释生成的。关于 Doxygen 注释规范本教程不作讲解,感兴趣的读者可自行搜索网络上的资料学习。

防止头文件包含重复

一般来说,我们不会直接在 C 的源文件写两个“#include”来包含同一个头文件,但可能因为头文件内部的包含导致重复,这种代码主要是避免这样的问题。

所以以bsp_led.h为例
“bsp_led.h”文件中使用了“#include“stm32f10x.h””语句,按习惯,可能我们写主程序的时候会在 main 文件写“#include“bsp_led.h”
及 #include“stm32f10x.h””,这个时候“stm32f10x.h”文件就被包含两次了,如果没有这种机制,就会出错。

#ifndef __LED_H
#define __LED_H

/* 此处省略头文件的具体内容 */

#endif /* end of __LED_H */

这里宏定义的名称是自己写的,最好和头文件保持一致
在头文件的开头,使用“#ifndef”关键字,判断标号“__LED_H”是否被定义,若没有被定义,则从“#ifndef”至“#endif”关键字之间的内容都有效,也就是说,这个头文件若被其它文件“#include”,
它就会被包含到其该文件中了,且头文件中紧接着使用“#define”关键字定义上面判断的标号“__LED_H”。当这个头文件被同一个文件第二次“#include”包含的时候,由于有了第一次包含中的“#define __LED_H”定义,这时再判断“#ifndef__LED_H”,判断的结果就是假了,从“#ifndef”至“#endif”之间的内容都无效,从而防止了同一个头文件被包含多次,编译时就不会出现“redefine
(重复定义)”的错误了。

  • 10
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

挽天技术

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值