不包含原型的函数类型的兼容性

问题描述 投票:0回答:1

有一个功能类型兼容性N2310 6.7.6.3(p15)的规则:

如果一种类型具有参数类型列表,而另一种类型已指定通过不属于函数定义的函数声明符,以及包含一个空的标识符列表,参数列表不应有一个省略号终止符,每个参数的类型应为与应用程序的类型兼容默认参数提升。

我可以想象一个例子:

#include <stdio.h>

int foo();

float bar();

int main(void){
    printf("%d\n", foo(1, 3)); //fine, int is unchanged by default argument promotion
    printf("%f\n", bar(1.0f, 2.0f)); //error, float is promoted to double
}

int foo(int a, int b){
    return a + b;
}

float bar(float b, float c){
    return b + c;
}

我发现矛盾的是6.5.2.2(p6)提到了:

如果参数数量不等于参数数量,行为是不确定的。

int foo()的情况下,其为空identifier-list。那么,调用printf("%d\n", foo(1, 3));是否会产生UB(提供了2个参数)?

无论如何,规则看起来很奇怪,有点不自然。是什么原因呢?我想与标准的早期版本具有向后兼容性...?

c language-lawyer function-call
1个回答
2
投票

C 2018 6.7.6.3 15告诉您两种类型是否兼容。因此可以用来比较两个声明。对于foo,您具有:

int foo();int foo(int a,int b){...}

其中,第二个具有参数列表,第一个由不属于函数定义且包含空标识符列表的函数声明指定。因此规则适用6.7.6.3 15。它说参数列表不应该带有省略号终止符(并且没有),并且每个参数的类型应该与默认参数提升产生的类型兼容(并且它们是兼容的,因为int产生int ])。

然后,对于bar,我们有:

float bar();
float bar(float b, float c) {...}

再次,适用6.7.6.3 15。但是在这种情况下,每个参数的类型都不是默认参数提升产生的,因为默认提升会将float转换为double。因此,这两个声明使用不兼容的类型声明bar

关于6.5.2.2 6:

…如果参数数量不等于参数数量,则行为未定义...

这是指实际函数的参数数量,而不是声明中的(空)列表中出现的参数数量。

无论如何,规则看起来很奇怪,有点不自然。是什么原因呢?我想与标准的早期版本具有向后兼容性...?

是的,C最初对函数声明比较松懈,允许使用空参数列表声明函数,如果我没记错的话,所有参数都与提升类型一起传递。随后,我们提供了对更严格和更精确的声明的支持,并且编写了规则,以允许旧代码继续运行。

© www.soinside.com 2019 - 2024. All rights reserved.