[英]C++ Compile time check if a microcontroller pin is already initialized from other source file
通常,微控制器的引脚可以通过端口号和引脚号来识别,两者都是编译时间常数。 引脚可以具有多种功能,如果在大型项目中使用,则多个源文件可以初始化同一引脚并破坏其他模块中实现的功能。
我想实现一个编译时间列表,该列表最初为空,并且每次初始化引脚时,都会检查该列表中是否已存在该引脚,如果存在,它将给出一个静态的断言,否则将在列表中插入引脚信息。 运行时不需要列表。
我对元编程没有足够的了解,如果有人可以为我提供实现的指导,那将是非常不错的。如果已经有一些用于此目的的库,请提供链接
您想要的是不可能的。 C ++元编程没有状态 ,它更像是一种功能性语言,而不是声明性语言。 因此,您不能拥有可变的列表。 可以通过创建新类型来引入唯一状态,但是没有可用的语法来检查是否声明或定义了特定的非嵌套名称。
多个源文件(编译单元)是独立编译的,因此肯定没有“全局状态”,这使它变得更加不可能。
另外,请注意,您所做的本质是运行时。 编译器没有工具来检查您是否两次调用了初始化函数。 这些调用可能隐藏在某些运行时if-else
决策之后。 并简单地编写HAL_GPIO_Init();
不管在整个程序中多少次都不是错误。
我能想到的最简单的事情是创建一个C ++单例类,该类负责与引脚进行通信。 您可以使用error_codes或异常(如果已启用)使用专用的int init_GPIO
方法。 代替static_assert
您将不得不依赖测试-单例可以正常工作,并且init_GPIO
的返回值不会被忽略。
如果您真的不想打扰单例,则此功能模板也可以使用:
template<std::size_t GPIO, std::size_t port> int GPIO_init(GPIO_InitStruct& s){
static bool initialized=false;
if(initialized) return <already_called>;
initialized=true;
//Assuming that you want to propagate the return value.
return HAL_GPIO_Init(GPIO, port, s);// Replace with the correct call.
}
如果需要线程安全的初始化,请使用:
template<std::size_t GPIO, std::size_t port> int GPIO_init(GPIO_InitStruct& s){
static std::once_flag initialized;
int ret_val = <already_called>;
auto call = [&](){ret_val = HAL_GPIO_Init(GPIO, port, s)};
std::call_once(initialized, call);
return ret_val;
}
假设每个驱动程序或HAL都有一个头文件,并且有一个main.cpp
包含所有这些头,则可以使用预处理器来完成此操作。
(可选)使用以下枚举创建项目范围的头文件“ pintype.h”:
// pintype.h
typedef enum
{
PIN_GPIO,
PIN_PWM,
PIN_ADC,
PIN_UART,
...
} pin_t;
然后,对于每个头文件,编写预处理程序检查,例如:
// pwm.h, header of the pwm driver or HAL
#include "pintype.h"
#ifdef PIN9
#error Pin 9 already taken
#else
#define PIN9 PIN_PWM
#endif
严格来说,不需要#error
,因为如果发生冲突,编译器将抱怨同一转换单元(main.cpp的定义)中的多个定义。
当编写驱动程序的开发人员收到错误消息时,他们可以转到引脚的预处理器定义,并找出项目中已经声明该功能的其他模块,而无需深入研究该驱动程序的内部实现。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.