快轉到主要內容

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

·1005 字·3 分鐘· loading
Habonroof
作者
Habonroof
一位漂流在軟體與硬體之間的邊緣行者,COVID期間被觸發想做技術部落格,目前還是剛出社會的新鮮人,除了工作也希望能在閒暇之餘撰寫教學文章與製作影片。現在正努力豐富網站內容中

本文介紹何謂##運算子,並且引用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