兼容类型(四)
2、联合的兼容性
具有不同作用域或者使用不同标记声明的联合类型是不同类型;具有相同作用域,并使用相同标记声明的联合类型是相同类型。
//u1具有文件作用域。 union u1{ int i; double d; }; //u2具有文件作用域。 union u2{ int i; double d; }; int main(void) { { //u1具有块作用域。 union u1{ int i; double d; }; ... } return 0; }
union u1和union u2是不同类型,因为标记不同;两处union u1类型是不同类型,因为作用域不同。
无标记联合类型以及不完整联合类型与同一编译单元内声明的其它联合类型不兼容。
union { int i; double d; } a; union { int i; double d; } b;
联合变量a和b具有不同的联合类型。
ISO/IEC 9899:2024标准前,如果联合声明包含联合成员列表,就在编译单元中声明了一个新类型,特定联合类型的内容最多定义一次,即联合类型不能重复定义;从ISO/IEC 9899:2024标准开始,允许联合类型重复定义。
/*test.c源文件。*/ #include <stdio.h> #include "myHeader.h" union u{ int i; double d; }; int main(void) { /*其它代码。*/ return 0; }
/*myHeader.h头文件。*/ #ifndef MYHEADER_H_INCLUDED #define MYHEADER_H_INCLUDED union u{ int i; double d; }; #endif // MYHEADER_H_INCLUDED
如果按ISO/IEC 9899:2024标准之前的标准(例如:ISO/IEC 9899:2018标准。)编译,将给出类似error: redefinition of 'union u'的出错信息;如果按ISO/IEC 9899:2024标准编译,重复定义是合法的。
使用相同标记声明的两个完整联合类型如果是兼容类型,应满足以下要求:
- 两个联合类型的联合成员必须一一对应,并且对应联合成员的类型是兼容类型;
- 如果一个联合成员声明时使用了对齐说明符,对应联合成员声明时应使用等价的对齐说明符;
- 如果一个联合成员是命名成员,对应联合成员应使用相同的名称声明;
- 同一编译单元内声明的两个联合类型中对应成员应以相同的顺序声明;
- 如果存在位字段,对应位字段的宽度应该是相同的。
匿名联合视为包含匿名联合的类型的常规成员,如果一个匿名联合的成员满足上述要求,该匿名联合的类型视为与另一个匿名联合的类型兼容。
以下情况不同编译单元中声明的两个联合类型是兼容的:
- 两个联合类型都是无标记联合类型,并且符合前面的要求。
- 两个联合类型具有相同的标记,在各自的编译单元内是完整类型,并且符合前面的要求。
- 两个联合类型具有相同的标记,并且至少一个联合类型在其编译单元内是不完整类型。
/* A编译单元。*/ union data;
/* B编译单元。*/ union data {int i; double d;};
/* C编译单元。*/ union data {int i; double dd;};
/* D编译单元。*/ union number {int i; double d;};
由于标记不同,A编译单元、B编译单元、C编译单元的联合类型与D编译单元内的联合类型是不兼容的。A编译单元内的联合类型与B编译单元、C编译单元内的联合类型是兼容的;A编译单元内的联合类型是不完整类型,B编译单元、C编译单元内的联合类型都是完整类型,在标记相同的情况下,不完整类型与完整类型是兼容的。B编译单元内的联合类型与C编译单元内的联合类型不兼容,它们都是完整类型,要求联合成员一一对应,联合成员名要求相同。
兼容类型不一定是相同类型;相同类型一定是兼容类型。
union { int i; double d; }a, b; union u{ int i; double d; }c; union u d;
联合变量a、b的类型是相同类型;联合变量c、d的类型是相同类型。