C++ 编译时检查微控制器引脚是否已从其他源文件初始化
C++ Compile time check if a microcontroller pin is already initialized from other source file
通常可以使用端口号和引脚 number.Both 来标识微控制器引脚,这些引脚是编译时间常数。
一个 pin 可以有多个功能,如果在一个大项目中使用多个源文件可以初始化相同的 pin 和 break 功能在其他模块中实现。
我想实现一个最初为空的编译时间列表,每次初始化一个 pin 时,它都会检查该 pin 是否已经
存在于该列表中,如果它存在,它将给出一个静态断言,否则它将在列表中插入引脚信息。 运行 时不需要列表。
我没有足够的元编程知识,如果有人能给我指导实现就太好了it.If已经有一些用于这种目的的库,请提供链接
你想要的是不可能的。 C++ 元编程没有 state,它更像是一种函数式语言而不是声明式语言。所以你不能有一个可变列表。唯一的状态可以通过创建新类型来引入,但是没有可用的语法来检查是否声明或定义了特定的 non-nested 名称。
多个源文件(编译单元)独立编译,肯定没有"global state",更不可能
此外,请注意,您所做的本质上是 run-time。编译器没有工具来检查您是否两次调用初始化函数。这些调用可能隐藏在某些 run-time if-else
决策的背后。而简单的写HAL_GPIO_Init();
无论在整个程序中写多少次都不会报错
我能想到的最简单的事情是创建一个 C++ 单例 class 来负责与引脚通信。如果启用,您可以使用 error_codes 或异常来使用专用的 int init_GPIO
方法。而不是 static_assert
你将不得不依赖测试 - 单例工作正常并且 init_GPIO
的 return 值不会被忽略。
如果你真的不想打扰单例,这个函数模板也可以:
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.
}
如果需要 thread-safe 初始化,则使用:
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;
}
假设每个 driver 或 HAL 都有一个 header 文件,并且有一个包含所有这些 header 的 main.cpp
,那么您可以使用pre-processor。
可选地,使用如下枚举创建 project-wide header "pintype.h":
// pintype.h
typedef enum
{
PIN_GPIO,
PIN_PWM,
PIN_ADC,
PIN_UART,
...
} pin_t;
然后对每个header文件,写一个pre-processor检查,例如:
// 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 的翻译单元)中有多个定义。
当编写 driver 的开发人员收到错误消息时,他们可以转到引脚的 pre-processor 定义并找出项目中的哪个其他模块已经声明了它,而无需挖掘 driver.
的内部实现
通常可以使用端口号和引脚 number.Both 来标识微控制器引脚,这些引脚是编译时间常数。 一个 pin 可以有多个功能,如果在一个大项目中使用多个源文件可以初始化相同的 pin 和 break 功能在其他模块中实现。
我想实现一个最初为空的编译时间列表,每次初始化一个 pin 时,它都会检查该 pin 是否已经 存在于该列表中,如果它存在,它将给出一个静态断言,否则它将在列表中插入引脚信息。 运行 时不需要列表。
我没有足够的元编程知识,如果有人能给我指导实现就太好了it.If已经有一些用于这种目的的库,请提供链接
你想要的是不可能的。 C++ 元编程没有 state,它更像是一种函数式语言而不是声明式语言。所以你不能有一个可变列表。唯一的状态可以通过创建新类型来引入,但是没有可用的语法来检查是否声明或定义了特定的 non-nested 名称。
多个源文件(编译单元)独立编译,肯定没有"global state",更不可能
此外,请注意,您所做的本质上是 run-time。编译器没有工具来检查您是否两次调用初始化函数。这些调用可能隐藏在某些 run-time if-else
决策的背后。而简单的写HAL_GPIO_Init();
无论在整个程序中写多少次都不会报错
我能想到的最简单的事情是创建一个 C++ 单例 class 来负责与引脚通信。如果启用,您可以使用 error_codes 或异常来使用专用的 int init_GPIO
方法。而不是 static_assert
你将不得不依赖测试 - 单例工作正常并且 init_GPIO
的 return 值不会被忽略。
如果你真的不想打扰单例,这个函数模板也可以:
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.
}
如果需要 thread-safe 初始化,则使用:
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;
}
假设每个 driver 或 HAL 都有一个 header 文件,并且有一个包含所有这些 header 的 main.cpp
,那么您可以使用pre-processor。
可选地,使用如下枚举创建 project-wide header "pintype.h":
// pintype.h
typedef enum
{
PIN_GPIO,
PIN_PWM,
PIN_ADC,
PIN_UART,
...
} pin_t;
然后对每个header文件,写一个pre-processor检查,例如:
// 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 的翻译单元)中有多个定义。
当编写 driver 的开发人员收到错误消息时,他们可以转到引脚的 pre-processor 定义并找出项目中的哪个其他模块已经声明了它,而无需挖掘 driver.
的内部实现