C語言中的##運算子|在PMBus範例中的使用方法

本文介紹何謂##運算子,並且引用TI C2000微處理器的公開範例PMBus communication stack說明這個預編譯器所使用的符號,目的是將兩個token組合成一個新字符。與巨集相似,會在實際編譯前先對原始碼進行處理,之後才依序進行連結、組合。{alertInfo}

目錄

    前言

    在TI原廠提供的PMBus範例*中,有一個巨集令我印象深刻,在每個PMBus target handler之前都有一串 PMBUS_STACK_FILENUM(N),用法就像pmbus_status_config.c中的方式,在每個獨立function前新增一句。

    PMBus範例

    File: pmbus_state_config.c
    #ifndef PMBUS_OVER_I2C
    //
    // Includes
    //
    #include "stdint .h"
    #include "stdbool .h"
    #include "pmbus_stack_config.h"
    
    //
    // Defines
    //
    PMBUS_STACK_FILENUM(1)
    
    #define PMBUS_STACK_TARGET_ADDRESS  0U
    #define PMBUS_STACK_TARGET_MASK     0x7FU
    
    //
    // Globals
    //
    PMBus_StackObject PMBusStackTarget;
    PMBus_StackHandle PMBusStackTargetHandle = &PMBusStackTarget;
    
    //***************************************************************************
    //
    // PMBusStack_initModule
    //
    //***************************************************************************
    bool PMBusStack_initModule(PMBus_StackHandle handle, const uint32_t moduleBase,
                               uint16_t *buffer)
    {
    
    點開位於pmbus_stack_assert.h 發現巨集宣告可以展開成
    //! Assign a "unique" number to each file, compiler error
    //! on duplicates
    #define PMBUS_STACK_FILENUM(number)   \
    enum{FILE_NUM = number};    \
    void _nullFunction##number(void){}
    

    ##運算子說明

    從字面上看,這個巨集為每個檔案宣告不同ID,當ID重複時編譯器會報錯。這樣做的意義推測是避免重複宣告。

    但這裡頭用到##運算子,因為出現的機率實在是太少,網路搜尋了一波,發現是預編譯器語法的一種 token-pasting operator 。
    他會把原本function中呼叫的第一個與第二個參數(token)做合併,要注意不是把變數家再一起,而是直接把原始碼中的字串做合併。
    舉例來說,有一個cancat函數使用a與b兩個參數(token)
    先不管它實際上在做什麼,我們定義concat(a,b) a##b 會把source code中所有concat(a,b)直接轉換成ab字串

    
    #include "stdio.h"
    #define concat(a, b) a##b
    int main(void)
    {
    	int xy = 30;
    	printf("%d", concat(x, y));
    	return 0;
    }
    

    因此,以上程式碼再經過預編譯(pre-conpile)後會變成:

    
    #include "stdio.h"
    #define concat(a, b) a##b
    int main(void)
    {
    	int xy = 30;
    	printf("%d", ab);
    	return 0;
    }
    

    總結

    回到pmbus的範例,number是被PMBUS_STACK_FILENUM 調用的token,所以下面
    void _nullFunction##number(void){}
    經過預編譯器會變成void _nullFunctionnumber(void){}
    舉例來說 PMBUS_STACK_FILENUM(1)會變成
    void _nullFunction1(void){}

    以上是研究PMBus Driverlib 的一些小發現

    參考資料

    *範例位/ti/c2000/C2000Ware_4_03_00_00/libraries/communications/PMBus/c28/pmbus_stack_project
    *巨集位於/ti/c2000/C2000Ware_4_03_00_00/libraries/communications/PMBus/c28/include/
    pmbus_stack_assert.h

    Post a Comment

    留個言吧

    較新的 較舊