[英]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.