在上一节中,我们通过一个复数存储表示抽象层把complex_struct
结构体的存储格式和上层的复数运算函数隔开,complex_struct
结构体既可以采用直角座标也可以采用极座标存储。但有时候需要同时支持两种存储格式,比如先前已经采集了一些数据存在计算机中,有些数据是以极座标存储的,有些数据是以直角座标存储的,如果要把这些数据都存到complex_struct
结构体中怎么办?一种办法是complex_struct
结构体采用直角座标格式,直角座标的数据可以直接存入complex_struct
结构体,极座标的数据先用make_from_mag_ang
函数转成直角座标再存,但转换总是会损失精度的。这里介绍另一种办法,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,这些常量的类型就是int
。有一点需要注意,结构体的成员名和变量名不在同一命名空间,但枚举的成员名和变量名却在同一命名空间,所以会出现命名冲突。例如这样是不合法的:
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; }