X巨集
外观
X巨集(X macros)是编程语言巨集裡的經典用法,可以產生類似列表的資料結構或是程式結構,常用在列表中部份內容無法用indexing合成的情形(例如在编译期就要產生)。若要維護列表,其對應項需要以相同的順序聲明或執行,可以用X巨集可靠的維護此部份程式。
這類列表的例如包括陣列的初始化(與枚舉常數和函數原型的聲明一起),敘述序列和switch語句的生成等。
X巨集的使用可以追溯到1960年代[1],在現今的C语言和C++語言中仍可使用,但和其他語言特性相比較,知道X巨集的人比較少[2][3]。
實現
[编辑]X巨集包括兩部份:
- 列表元素的定義
- 列表的展開,產生部份的宣告或是敘述
列表是由巨集或是標頭檔所定義(命名為LIST),本身不會產生程式碼,只包括了一連串巨集(命名為X)列表,巨集會依該順序進行,列表中也包括列表元素的資料。每一個引用列表LIST時,會加上要執行的巨集。列表LIST展開時,會將X改為真正要執行的巨集,該巨集就會針對列表的每一個元素依序處理,產生資料或是程式碼。
範例1
[编辑]此例中定義一個變數列表,並且可以自動產生其宣告敘述,以及用printf顯示的敘述。
首先是列表定義。列表可以包括多個引數,不過目前只使用變數名稱。
#define LIST_OF_VARIABLES \
X(value1) \
X(value2) \
X(value3)
接著將此列表展開,以此產生變數宣告:
#define X(name) int name;
LIST_OF_VARIABLES
#undef X
用類似的方式,可以產生用prints顯示變數和值的敘述:
void print_variables(void)
{
#define X(name) printf("%s = %d\n", #name, name);
LIST_OF_VARIABLES
#undef X
}
透過C预处理器,會產生以下的程式碼。其中的換行和縮排是方便閱讀才放上去的,预处理器其實不會產生換行和縮排:
int value1;
int value2;
int value3;
void print_variables(void)
{
printf("%s = %d\n", "value1", value1);
printf("%s = %d\n", "value2", value2);
printf("%s = %d\n", "value3", value3);
}
範例2,用X巨集為參數
[编辑]此範例設法提高X巨集的可讀性:
- 定義列表的巨集名稱前面加上FOR_。
- 將工作巨集以參數方式傳遞給列表巨集。一方面可以避免定義一個名稱無法表示用途的巨集X,也避免後續需要undefine該巨集。
- 使用可变参数宏...的語法在工作巨集中,使其在需要時可以接收更多的參數。這可以讓程式維護者可以視需要增加欄位,但不需更新整個巨集的定義。
- 使用名稱DO作為列表巨集中引數巨集的名稱。
#define FOR_LIST_OF_VARIABLES(DO) \
DO(id1, name1) \
DO(id2, name2) \
DO(id3, name3)
同上,依此表可以產生以下的變數宣告:
#define DEFINE_NAME_VAR(id, name, ...) int name;
FOR_LIST_OF_VARIABLES( DEFINE_NAME_VAR )
或是宣告enumeration:
#define DEFINE_ENUMERATION(id, name, ...) name = id,
enum IdListType
{
FOR_LIST_OF_VARIABLES( DEFINE_ENUMERATION )
};
用類似方式,也可以產生用printf顯示變數和名稱的程式。
void print_variables(void)
{
#define PRINT_NAME_AND_VALUE(id, name, ...) printf(#name " = %d\n", name);
FOR_LIST_OF_VARIABLES( PRINT_NAME_AND_VALUE )
}
相關條目
[编辑]參考資料
[编辑]- ^ Meyers, Randy. The New C: X Macros. Dr.Dobb's 2001.
- ^ Bright, Walter. The X Macro. Digital Mars 2010
- ^ Lucas, Andrew. Reduce C-language coding errors with X macros. Embedded.com 2013