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