【關鍵詞】反射機制;元信息;抽象;數據結構圖
反射(Reflection)的概念是由Smith在1982年首次提出的,主要是指程序可以訪問、檢測和修改它本身狀態或行為的一種能力。
編程語言反射機制[1]可以自動生成元信息,依賴這些元信息,程序可以動態地訪問、檢測,以及修改對象。反射機制有著廣泛應用[2],例如:持久化、配置文件導入導出,以及框架開發[3]等等,是一種既靈活又強大的編程語言特性。
元信息,也稱為元數據,是描述數據的數據,它提供了關于數據的基本屬性和特征的信息。元信息在計算機領域有著廣泛的應用,例如:文件系統中,元信息通常用于描述文件的基本屬性,可能包括文件名、文件大小、創建日期,以及修改日期等,這些元信息有助于文件系統更好地管理文件;數據庫中,元信息用于描述表的結構、類型,以及約束等信息,幫助數據庫更好地管理數據。總之,元信息是一種非常重要的數據資源,它提供了關于數據的基本信息和特征,有助于我們更好地管理和理解數據。

元信息在反射機制中扮演著至關重要的角色,它是反射機制得以有效運作的核心要素。反射機制允許程序在運行時獲取和操作對象的信息,完全是基于元信息實現的。元信息通常包括關于對象的類型、結構、屬性和方法等各方面的詳細描述,通過反射機制,程序可以查詢這些元信息,從而了解對象的內部狀態和行為;同時使得程序能夠在運行時動態地修改對象的狀態、調用方法或
軟件開發中,存在一種如圖1所示的關系,結構體是現實的抽象,元信息是結構體的抽象,最后元信息又是自身的抽象。
C語言支持對現實的抽象,一般使用結構體,推廣到其他類型亦可。C語言提供完備的類型系統,包括:整型、浮點、結構體、數組、指針、枚舉,以及聯合體等類型,并且允許數據結構彼此以嵌套、鏈接,以及遞歸等方式組合。
基于C語言類型系統多樣的組合方式,不僅可以構建樹型數據結構,還可以構建更加復雜的圖狀數據結構。數據結構圖[4]是用來展示數據內部結構的,例如:圖2是list的數據結構圖。以數據結構圖為依據,C語言類型可以分兩類:簡單類型包括整型、浮點、字符,以及枚舉,在數據結構圖中只能是邊界節點,即被箭頭指向,不能作為箭頭起始;復合類型包括結構體、聯合體、數組,以及指針,在圖中可以擔當中間節點,連接箭頭尾部。

以直接或間接實例化成變量為依據,C語言類型可以分成兩類:可直接實例化類型包括整型、浮點、字符、數組,以及指針;間接實例化類型包括結構體、聯合體,以及枚舉,例如結構體類型不能直接實例化成結構體變量,需要實例化成具體結構體,即在代碼中定義結構體,然后再實例化該具體結構體成為變量。
但是C語言抽象鏈表是不完整的,缺失元信息內容,所以不支持反射機制。元信息是結構體的抽象,本質是描述C語言類型的結構體。元信息的設計就是,對描述各類型所需屬性的整理匯總,如下所示:
元信息既是結構體,又是結構體的抽象,這就不難解釋元信息可以抽象自身。
反射機制通過提供接口將元信息與程序的實際執行過程相結合。Java常用的反射機制訪問接口,根據不同類型提供不同函數,由調用者選擇,如下所示:
publicObjectget(Object)
publicbooleangetBoolean(Object)
publicbytegetByte(Object)
publicchargetChar(Object)
publicshortgetShort(Object)
publicintgetInt(Object)
publiclonggetLong(Object)
publicfloatgetFloat(Object)
publicdoublegetDouble(Object)
publicvoidset(Object,Object)
publicvoidsetBoolean(Object,boolean)
publicvoidsetByte(Object,byte)
publicvoidsetChar(Object,char)
publicvoidsetShort(Object,short)
publicvoidsetInt(Object,int)
publicvoidsetLong(Object,long)
publicvoidsetFloat(Object,float)
publicvoidsetDouble(Object,double)
反射機制接口設計原理,是以元信息為地圖,按圖索驥訪問變量,賦值或者獲取變量值。Java反射訪問接口函數繁多,主要因為設計上用不同函數承載不同類型,而Java又具備豐富的類型系統。為了簡化接口,本文采用了輸入輸出參數承載類型的設計策略,對外只提供了getter和setter函數:函數getter輸入參數需要變量地址、字段路徑,以及元信息,輸出請求的值;函數setter輸入參數需要變量地址、字段路徑、元信息,以及要設置的值。由于C語言類型系統同樣豐富,不同類型的值體現不同的特征,若用接口函數的值參數承載類型,值參數同樣需要具備相應的類型系統。本文借用JSON類型系統,直接使用cJSON作為值參數,其中cJSON是應用廣泛的JSON庫。反射機制訪問接口包括三大要素:變量是被賦值和獲取的主體;元信息是變量組織結構信息地圖,根據地圖才能找到待訪問字段;cJSON是設置或者獲取的值,自身包括待訪問字段路徑,本文設計反射機制訪問接口如下:
intget_each_value_of_fields(void*obj,meta_t*meta,cJSON*value)
intset_each_value_of_fields(void*obj,meta_t*meta,cJSON*value)
其中C語言類型系統與cJSON值類型系統映射關系如下:

程序開發過程存在多個維度:開發者維度、代碼維度,以及程序維度。開發者直接控制代碼維度,間接控制程序維度;代碼維度直接控制程序維度;程序維度自成系統。結構體處于代碼維度,不可進入程序維度,實際上只有變量才可以攜帶數據,并存在于程序維度;因此只有創建了對應的元信息變量的類型才支持反射,所以不僅需要抽象出元信息結構體,也需要為其創建元信息變量。本文將這些抽象出來的元信息結構體稱為元結構體,是元信息的抽象;把元結構體實例化的變量稱為元變量,是元信息的載體。

將變量補充到抽象鏈圖中,如圖3所示:實例化了結構體的變量,描述現實對象的基本屬性;實例化了抽象結構體的元信息的變量,描述了結構體的基本屬性;實例化了抽象元信息的元信息的變量,描述了元信息的基本屬性;元信息的自描述屬性,阻止了抽象鏈的無限增長。
C語言不支持反射機制,元信息在程序維度不存在,它存在于代碼維度,受開發者維度控制;如何在程序維度獲取元信息,是創建元信息的方法要解決的本質問題。創建元信息,就是創建元變量,可用于創建其他類型變量的方式,都適用于創建元變量;最簡單方式就是直接定義變量,然后開發者負責根據待反射結構體對各個字段進行初始化,整個過程是靜態的,由開發者控制,語言級別沒有提供任何輔助。

本文的簡單反射機制,實現了C語言結構體定義代碼解析器,可以解析結構體定義的字符串,生成相應的元變量;還提供了若干宏接口,簡化創建元信息過程,設計函數和宏如下:
本文實現的C語言簡單反射機制,可以應用到各種場景,例如:配置文件導入導出、生成監控報表、序列化,以及restful接口實現等;并且極大簡化了其開發難度,例如:配置文件導入導出模塊結構如圖4所示,首先根據配置需求編寫配置結構體,然后為配置結構體創建元變量,接著實例化配置結構體成為配置變量,最后就可以通過getter/setter簡單地實現配置文件導入導出。
本文實現的C語言簡單反射機制,提供了基本的反射功能,具備較廣泛的應用場景。但簡單反射機制還有很多待改進地方,例如:不支持數據結構圖存在回環結構情況;尚不支持位段類型,位段是一種特殊類型,它委托給其他類型用于訪問,但不支持地址操作,而自身只做位數限制。