兼容类型(五)
3、枚举的兼容性
ISO/IEC 9899:2018标准规定:枚举常量的类型应为int类型;枚举类型应与char类型、有符号整数类型或者无符号整数类型兼容。ISO/IEC 9899:2024标准规定:在无固定底层类型(fixed underlying type)的情况下,枚举常量(又称枚举成员)的类型可以是int类型,也可以是枚举类型;在未显式指定底层类型的情况下,枚举类型应与char类型、标准或者扩展有符号整数类型、标准或者扩展无符号整数类型中的一个兼容(bool类型和位精确整数类型除外。),具体由实现定义,但应能表示所有枚举成员值。
上述情况下,枚举常量的类型和枚举类型可能是相同类型,也可能是不同类型。
#define TYPE(x) _Generic((x), \ int: "int type", \ char: "char type", \ unsigned int: "unsigned int type", \ long: "long type", \ default: "other type" \ ) enum color {red, green, blue}; ... enum color myCar; printf("%s\n", TYPE(myCar)); //输出unsigned int type。 printf("%s\n", TYPE(red)); //输出int type。
这里枚举常量的类型是int类型;枚举类型是unsigned int类型。不同实现可能存在差异。
(注:使用gcc编译器编译,版本号12.4.0。)
ISO/IEC 9899:2024标准规定:底层类型可以使用枚举类型说明符明确指定,指定的类型是枚举类型的固定底层类型。这种情况下,枚举成员类型是枚举类型,枚举类型与枚举固定底层类型兼容。
enum color : unsigned {red, green, blue}; enum color myCar;
枚举变量myCar与枚举常量red、green、blue具有相同类型,均与unsigned类型兼容。
如果两个枚举说明符包含的枚举类型说明符声明了相同的类型,则其底层类型应是兼容类型。
enum car : unsigned; enum plane : unsigned;
枚举类型enum car和枚举类型enum plane的底层类型是兼容类型。
具有不同作用域或者使用不同标记声明的枚举类型是不同类型;具有相同作用域,并使用相同标记声明的枚举类型是相同类型。
//e1具有文件作用域。 enum e1{red, green, blue}; //e2具有文件作用域。 enum e2 : int; int main(void) { { //e1具有块作用域。 enum e1{red, green, blue}; ... } return 0; }
enum e1和enum e2是不同类型,因为标记不同;两处enum e1类型是不同类型,因为作用域不同。
无标记枚举类型以及不完整枚举类型与同一编译单元内声明的其它枚举类型不兼容。
enum {red, green, blue} a; { enum {red, green, blue} b; }
枚举变量a和b具有不同的枚举类型。
ISO/IEC 9899:2024标准前,如果枚举声明包含枚举成员列表,就在编译单元中声明了一个新类型,特定枚举类型的内容最多定义一次,即枚举类型不能重复定义;从ISO/IEC 9899:2024标准开始,允许枚举类型重复定义。
/*test.c源文件。*/ #include <stdio.h> #include "myHeader.h" enum color {red, green, blue}; int main(void) { /*其它代码。*/ return 0; }
/*myHeader.h头文件。*/ #ifndef MYHEADER_H_INCLUDED #define MYHEADER_H_INCLUDED enum color {red, green, blue}; #endif // MYHEADER_H_INCLUDED
如果按ISO/IEC 9899:2024标准之前的标准(例如:ISO/IEC 9899:2018标准。)编译,将给出类似error: redeclaration of 'enum color'的出错信息;如果按ISO/IEC 9899:2024标准编译,重复定义是合法的。
使用相同标记声明的两个完整枚举类型如果是兼容类型,应满足以下要求:
- 两个枚举类型的枚举成员必须一一对应,并且对应枚举成员的类型是兼容类型;
- 如果一个枚举成员声明时使用了对齐说明符,对应枚举成员声明时应使用等价的对齐说明符;
- 如果一个枚举成员是命名成员,对应枚举成员应使用相同的名称声明;
- 对应枚举成员应具有相同值;
- 如果一个枚举类型具有固定底层类型,另一个枚举类型应具有兼容的固定底层类型。
以下情况不同编译单元中声明的两个枚举类型是兼容的:
- 两个类型都是无标记枚举类型,并且符合前面的要求。
- 两个枚举类型具有相同的标记,在各自的编译单元内是完整类型,并且符合前面的要求。
- 两个枚举类型具有相同的标记,并且至少一个枚举类型在其编译单元内是未完成的。
/* A编译单元。*/ enum color : unsigned;
/* B编译单元。*/ enum color : unsigned {red, green, blue};
/* C编译单元。*/ enum color : unsigned {black, white};
/* D编译单元。*/ enum colour : unsigned;
由于标记不同,A编译单元、B编译单元、C编译单元的枚举类型与D编译单元内的枚举类型是不兼容的。A编译单元内的枚举类型与B编译单元、C编译单元内的枚举类型是兼容的;A编译单元内的枚举类型是完整类型,但缺少枚举成员;B编译单元、C编译单元内的枚举类型都是完整类型,包含枚举成员。B编译单元内的枚举类型与C编译单元内的枚举类型不兼容,它们都是完整类型,要求枚举成员一一对应,枚举成员名要求相同。
兼容类型不一定是相同类型;相同类型一定是兼容类型。
enum {black, white} a, b; enum color {red, green, blue} c; enum color d;
枚举变量a、b的类型是相同类型;枚举变量c、d的类型是相同类型。