接上篇筆記我們分享的是RTT的pin設備驅動:「RT-Thread筆記」IO設備模型及PIN設備,其中用到PIN驅動框架中的pin_mode函數來設置引腳的模式:
void rt_pin_mode(rt_base_t pin,rt_base_t mode);
這裡的引腳編号pin需要和芯片的引腳号區分開來,它們并不是同一個概念,引腳編号由PIN設備驅動程序定義,和具體的芯片相關。其實,驅動代碼drv_gpio.c文件一個結構體數組存放了每個PIN腳對應的編号信息,如:
可以看到,__STM32_PIN是一個帶參宏,其用到##符号是個什麼東東?再看一下PIN結構體的定義如下:
/* STM32 GPIO driver */
struct pin_index
{
int index;
void (*rcc)(void);
GPIO_TypeDef *gpio;
uint32_t pin;
};
其中, __STM32_PIN中的内容為:
index:代表引腳編号
GPIO##gpio##_CLK_ENABLE:代表時鐘使能
GPIO##gpio:代表端口
GPIO_PIN_##gpio_index:代表引腳号
從這裡可以推出##符号起連接作用。假設這樣使用該宏:
__STM32_PIN(7, C, 13)
該宏将展開為:
{7, GPIOC_CLK_ENABLE, GPIOC, GPIO_PIN_13}
同時,常常與##符号一起用的還有#符号。下面看看這兩個你可能沒用過,但卻很有用的符号(運算符):
我們平時使用帶參宏時,字符串中的宏參數是沒有被替換的。例如:
輸出結果為:
然而,我們期望輸出的結果是:
5 20 = 25
13 14 = 27
這該怎麼做呢?其實,C語言允許在字符串中包含宏參數。在類函數宏(帶參宏)中,#号作為一個預處理運算符,可以把記号轉換成字符串。例如,如果A是一個宏形參,那麼#A就是轉換為字符串"A"的形參名。這個過程稱為字符串化(stringizing)。以下程序演示這個過程:
輸出結果為:
這就達到我們想要的結果了。所以,#運算符可以完成字符串化(stringizing)的過程。
與#運算符類似,##運算符可用于類函數宏(帶參宏)的替換部分。##運算符可以把兩個記号組合成一個記号。例如,可以這樣做:
#define XNAME(n) x##n
然後,宏XNAME(4)将展開x4。以下程序演示##運算符的用法:
輸出結果為:
注意:PRINT_XN()宏用#運算符組合字符串,##運算符把記号組合為一個新的标識符。
其實,##運算符在這裡看來并沒有起到多大的便利,反而會讓我們感覺到不習慣。但是,使用##運算符有時候是可以提高封裝性及程序的可讀性的。 比如上面的gpio驅動代碼中:
#define __STM32_PIN(index, gpio, gpio_index) \ { \ index, GPIO##gpio##_CLK_ENABLE, GPIO##gpio, GPIO_PIN_##gpio_index \ }
有些東西我們用得太少了,所以可能會誤以為沒有用,但實際上卻是很有用的,我們應當要多積累各個知識點。
以上就是關于#運算符與##運算符的筆記,用#運算符組合字符串,##運算符把記号組合為一個新的标識符。如有錯誤歡迎指出。資料:『RT-Thread-IoT代碼』、『C Primer Plus』。
,更多精彩资讯请关注tft每日頭條,我们将持续为您更新最新资讯!