复合类型
兼容类型(compatible type)和复合类型(composite type)有助于讨论类型声明不需要完全相同的情况,这对解释不完整类型(incomplete type)和完整类型(completed type)之间的关系特别有用。引入复合类型可以从不完整类型的声明中积累信息,例如:缺失数组大小的数组声明。
一、复合类型
复合类型可以由两个兼容类型构造而成。如果两个兼容类型是相同类型,那么复合类型也就是该类型;否则复合类型是与两个兼容类型都兼容的类型,并满足以下条件:
-- 如果两个类型都是结构类型或者联合类型,则通过其成员组成复合类型来递归确定复合类型。
-- 如果两个类型都是数组类型,以下规则将适用:
如果一个类型是已知常量大小的数组,那么复合类型就是该常量大小的数组。
int func(int []); int func(int [3]);
上述func函数的结果复合类型为int (int [3]),即函数参数为一个含有3个int类型元素的数组。
否则,如果一个类型是变长数组,其大小由一个未评估表达式指定,则行为是未定义的。
C语言中以下情况表达式不会被评估:
1、typeof运算符的操作数,操作数为可变修改类型(variably modified type)的情况除外。
2、sizeof运算符的操作数,操作数为变长数组类型(variable length array type)的情况除外。
3、alignof运算符的操作数。
4、泛型选择(generic selection)的控制表达式。
5、对于&&运算符,左操作数为0时,右操作数不会被评估。
6、对于||运算符,左操作数为1时,右操作数不会被评估。
unsigned n; size_t sz = sizeof(n=4); //表达式n=4不会被评估。 int arr[n]; //未定义行为。
否则,如果一个类型是指定大小的变长数组,那么复合类型是具有该大小的变长数组。
unsigned n = 3; int func(int []); int func(int [n]);
func函数的参数是一个变长数组,该数组含有3个int类型的数组元素。
否则,如果一个类型是未指定大小的变长数组,则复合类型是未指定大小的变长数组。
int func(int []); int func(int [*]);
func函数的参数是一个未指定大小的变长数组。
否则,如果两个类型都是未知大小的数组,则复合类型是未知大小的数组。
int func(int []); int func(signed []);
func函数的参数是一个未知大小的数组。
复合类型的元素类型是两个元素类型的复合类型。
-- 如果只有一个类型是带形参列表的函数类型(函数原型),那么复合类型是带形参列表的函数原型。
int func(); //旧风格函数声明。 int func(int); //函数原型。
func函数的返回类型是int类型,有一个int类型的形式参数。
(注:以上代码仅适用于ISO/IEC 9899:2018标准及之前标准;ISO/IEC 9899:2024标准淘汰了旧风格函数声明,int func();等价于int func(void);。)
-- 如果两个类型都是带形参列表的函数类型,那么复合类型形参列表中每个参数的类型就是相应参数的复合类型。
-- 如果一个类型具有标准属性,复合类型也应该具有该标准属性。
-- 如果两个类型都是枚举类型,复合类型也应该是枚举类型。
-- 如果一个类型是枚举类型,另一个类型是非枚举类型的整数类型,复合类型是否是枚举类型将由实现定义。
上述规则递归地适用于派生这两个类型的类型。
如果原始类型中的某个类型满足了复合类型的所有要求,那么复合类型是该类型,还是满足要求的其它类型,ISO/IEC 9899:2024标准未作明确规定。
对于在先前声明可见作用域内声明的具有内部链接或者外部链接的标识符,如果先前声明指定了内部链接或者外部链接,则后面声明的标识符类型将成为复合类型。
主要参考资料:
3、open-std.org : Rationale for Internationa Standard - Programming Languages - C
6、en.cppreference.com : function_declaration
7、ibm.com : Compatible and composite types
8、open-std.org : Composite Types V2