当前位置: C语言 -- 基础 -- 兼容类型

兼容类型(六)

五、函数类型的兼容性

C语言中函数声明存在两种风格:一种函数声明时指定形式参数的类型,称为函数原型(function prototype);另一种函数声明时不指定函数参数的类型,称为旧风格(old-style)。

int funcOne(int income);    //函数原型。
int funcTwo();              //旧风格。

funcOne的声明是函数原型;funcTwo的声明是旧风格。

ISO/IEC 9899:2024标准规定:对于不存在形参类型列表的函数声明,其效果与声明了包含关键词void的形参类型列表的函数相同。根据ISO/IEC 9899:2024标准,int funcTwo();等价于int funcTwo(void);


函数定义也存在是否包含函数原型的情况。根据ISO/IEC 9899:2018标准第6.11.6 Function declarators节及第6.11.7 Function definitions节,不使用函数原型的函数声明、不使用函数原型的函数定义是一种过时做法;ISO/IEC 9899:2024标准删除了旧风格函数声明、函数定义的相关内容;因此本文讨论函数类型兼容性时将主要讨论使用函数原型声明的函数。


函数类型有两个重要特征,一个是函数的返回类型,另一个是函数形参的数量和类型。如果两个函数类型兼容,要求函数的返回类型兼容,形参数量相等,对应形参类型兼容(如果两个函数类型都是旧风格的,形参类型将不会比较。)。

int a(int);
int b(int);
int c(int, int);
float d(int);
int e(int, double);

ab的类型是兼容的;ac的类型不兼容,因为形参数量不同;ad的类型不兼容,因为函数返回类型不同;ae的类型不兼容,因为形参数量不同;ce的类型不兼容,因为有一个形参类型不兼容。


关于函数参数兼容的几种特殊情况:

① 函数参数包含省略号。

省略号(...)作为函数形参表示函数具有可变数量的参数,两个兼容类型的函数,如果一个使用了省略号,另一个应该对应的使用省略号。

int a(int, ...);
int b(int, ...);
int c(int, int);

ab的类型是兼容的;abc的类型是不兼容的。

ISO/IEC 9899:2024标准之前的标准要求:省略号前应至少存在一个形参。ISO/IEC 9899:2024标准取消了这种限制,省略号可以在没有前一个参数的情况下出现。)


② 函数参数为数组类型。

函数声明时,如果函数形参是数组类型,函数参数与对应的指针类型兼容。

int a(int *);
int b(int [*]);

ab的类型是兼容的,其中a的参数是一个int类型的指针;b的参数是一个int类型的变长数组,数组类型会转换成对应的指针类型。


③ 函数参数为函数类型。

函数声明时,如果函数形参是函数类型,函数参数与对应的指针类型兼容。

int a(int (void));
int b(int (*)(void));

ab的类型是兼容的,其中a的参数是一个返回类型为int类型、没有参数的函数,函数类型会转换成对应的指针类型;b的参数是一个指向返回类型为int类型、没有参数的函数的指针。


④ 函数参数存在类型限定符的情况。

顶级类型限定符(top-level qualifier)是限定对象自身的类型限定符,以const类型限定符为例:

int numberOne = 10;
const int numberTwo = 5;
const int *ptrOne = &numberTwo;
int * const ptrTwo = &numberOne;
const int * const ptrThree = &numberTwo;

如果const是顶级类型限定符,其限定对象的值是不能改变的;其限定对象只能初始化,初始化后不能再被赋值。

对于numberTwo,类型限定符是顶级类型限定符,numberTwo的值是不能改变的;对于ptrOne,类型限定符不是顶级类型限定符,const限定的是指针指向的对象,而不是指针自身,指针ptrOne还可以指向其它实体;对于ptrTwo,类型限定符是顶级类型限定符,其限定的是指针自身,ptrTwo只能指向变量numberOne,而不能指向其它实体,指针指向位置是不变的;对于ptrThree*号左边的const不是顶级类型限定符,其限定的是指针指向的对象,*号右边的const是顶级类型限定符,其限定的是指针自身。

:顶级类型限定符不是ISO/IEC 9899:2018ISO/IEC 9899:2024标准中的术语。)


如果函数形参中出现了顶级类型限定符,将和没有顶级类型限定符的非限定版本兼容。

int a(int);
int b(const int);
int c(int *);
int d(int * const);

bd中的const类型限定符均为顶级类型限定符,如果没有顶级类型限定符,ab的参数类型是相同的,cd的参数类型是相同的;所以这里ab的函数类型是兼容的,cd的函数类型是兼容的。




主要参考资料:

1、ISO/IEC 9899:2024

2、ISO/IEC 9899:2018

3、ibm.com : Compatible and composite types

4、open-std.org : Rationale for Internationa Standard - Programming Languages - C

5、open-std.org : Improved Rules for Tag Compatibility(updates N3032)