「C語言筆記」#運算符與##運算符

接上篇筆記我們分享的是RTT的PIN設備驅動: ,其中用到PIN驅動框架中的pin_mode函數來設置引腳的模式:

<code>void rt_pin_mode(rt_base_t pin,rt_base_t mode);/<code>

這裡的引腳編號pin需要和芯片的引腳號區分開來,它們並不是同一個概念,引腳編號由PIN設備驅動程序定義,和具體的芯片相關。其實,驅動代碼drv_gpio.c文件一個結構體數組存放了每個PIN腳對應的編號信息,如:

「C語言筆記」#運算符與##運算符


可以看到,__STM32_PIN是一個帶參宏,其用到##符號是個什麼東東?再看一下PIN結構體的定義如下:

<code>/* STM32 GPIO driver */
struct pin_index
{
   int index;
   void (*rcc)(void);
   GPIO_TypeDef *gpio;
   uint32_t pin;
};/<code>

其中, __STM32_PIN中的內容為:

<code>index:代表引腳編號
GPIO##gpio##_CLK_ENABLE:代表時鐘使能
GPIO##gpio:代表端口
GPIO_PIN_##gpio_index:代表引腳號/<code>

從這裡可以推出##符號起連接作用。假設這樣使用該宏:

<code> __STM32_PIN(7, C, 13) /<code>

該宏將展開為:

<code>{7, GPIOC_CLK_ENABLE, GPIOC, GPIO_PIN_13}/<code>

同時,常常與##符號一起用的還有#符號。下面看看這兩個你可能沒用過,但卻很有用的符號(運算符):


1、#運算符

我們平時使用帶參宏時,字符串中的宏參數是沒有被替換的。例如:

「C語言筆記」#運算符與##運算符


輸出結果為:

「C語言筆記」#運算符與##運算符


然而,我們期望輸出的結果是:

<code>5 + 20 = 25
13 + 14 = 27/<code>

這該怎麼做呢?其實,C語言允許在字符串中包含宏參數。在類函數宏(帶參宏)中,#號作為一個預處理運算符,可以把記號轉換成字符串。例如,如果A是一個宏形參,那麼#A就是轉換為字符串"A"的形參名。這個過程稱為字符串化(stringizing)。以下程序演示這個過程:

「C語言筆記」#運算符與##運算符


輸出結果為:

「C語言筆記」#運算符與##運算符


這就達到我們想要的結果了。所以,#運算符可以完成字符串化(stringizing)的過程。

2、##運算符

與#運算符類似,##運算符可用於類函數宏(帶參宏)的替換部分。##運算符可以把兩個記號組合成一個記號。例如,可以這樣做:

<code>#define XNAME(n) x##n/<code>

然後,宏XNAME(4)將展開x4。以下程序演示##運算符的用法:

「C語言筆記」#運算符與##運算符


輸出結果為:

「C語言筆記」#運算符與##運算符


注意:PRINT_XN()宏用#運算符組合字符串,##運算符把記號組合為一個新的標識符。

其實,##運算符在這裡看來並沒有起到多大的便利,反而會讓我們感覺到不習慣。但是,使用##運算符有時候是可以提高封裝性及程序的可讀性的。 比如上面的gpio驅動代碼中:

<code>#define __STM32_PIN(index, gpio, gpio_index) \\
{ \\
index, GPIO##gpio##_CLK_ENABLE, GPIO##gpio, GPIO_PIN_##gpio_index \\
}/<code>

有些東西我們用得太少了,所以可能會誤以為沒有用,但實際上卻是很有用的,我們應當要多積累各個知識點。

以上就是關於#運算符與##運算符的筆記,用#運算符組合字符串,##運算符把記號組合為一個新的標識符。如有錯誤歡迎指出。資料:『RT-Thread-IoT代碼』、『C Primer Plus』。


分享到:


相關文章: