在上一節中,我們通過一個複數存儲表示抽象層把complex_struct
結構體的存儲格式和上層的複數運算函數隔開,complex_struct
結構體既可以採用直角座標也可以採用極座標存儲。但有時候需要同時支持兩種存儲格式,比如先前已經採集了一些數據存在計算機中,有些數據是以極座標存儲的,有些數據是以直角座標存儲的,如果要把這些數據都存到complex_struct
結構體中怎麼辦?一種辦法是規定complex_struct
結構體採用直角座標格式,直角座標的數據可以直接存入complex_struct
結構體,而極座標的數據先轉成直角座標再存,但由於浮點數的精度有限,轉換總是會損失精度的。這裡介紹另一種辦法,complex_struct
結構體由一個數據類型標誌和兩個浮點數組成,如果數據類型標誌為0,那麼兩個浮點數就表示直角座標,如果數據類型標誌為1,那麼兩個浮點數就表示極座標。這樣,直角座標和極座標的數據都可以適配(Adapt)到complex_struct
結構體中,無需轉換和損失精度:
enum coordinate_type { RECTANGULAR, POLAR }; struct complex_struct { enum coordinate_type t; double a, b; };
enum
關鍵字的作用和struct
關鍵字類似,把coordinate_type
這個標識符定義為一個Tag,struct complex_struct
表示一個結構體類型,而enum coordinate_type
表示一個枚舉(Enumeration)類型。枚舉類型的成員是常量,它們的值由編譯器自動分配,例如定義了上面的枚舉類型之後,RECTANGULAR
就表示常量0,POLAR
表示常量1。如果不希望從0開始分配,可以這樣定義:
enum coordinate_type { RECTANGULAR = 1, POLAR };
這樣,RECTANGULAR
就表示常量1,而POLAR
表示常量2。枚舉常量也是一種整型,其值在編譯時確定,因此也可以出現在常量表達式中,可以用於初始化全局變數或者作為case
分支的判斷條件。
有一點需要注意,雖然結構體的成員名和變數名不在同一命名空間中,但枚舉的成員名卻和變數名在同一命名空間中,所以會出現命名衝突。例如這樣是不合法的:
int main(void) { enum coordinate_type { RECTANGULAR = 1, POLAR }; int RECTANGULAR; printf("%d %d\n", RECTANGULAR, POLAR); return 0; }
complex_struct
結構體的格式變了,就需要修改複數存儲表示層的函數,但只要保持函數介面不變就不會影響到上層函數。例如:
struct complex_struct make_from_real_img(double x, double y) { struct complex_struct z; z.t = RECTANGULAR; z.a = x; z.b = y; return z; } struct complex_struct make_from_mag_ang(double r, double A) { struct complex_struct z; z.t = POLAR; z.a = r; z.b = A; return z; }