【问题标题】:Compatibility of function types that does not include a prototype不包含原型的函数类型的兼容性
【发布时间】:2019-10-12 10:09:26
【问题描述】:

函数类型兼容性有一个规则N23106.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 个参数)?

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

【问题讨论】:

  • bar(1.0, 2.0)1.02.0 中不会提升为double。他们是double

标签: c language-lawyer function-call


【解决方案1】:

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

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

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

那么,对于bar,我们有:

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

同样,6.7.6.3 15 适用。但是在这种情况下,每个参数都有一个不是默认参数提升的类型,因为默认提升将float 转换为double。所以这两个声明用不兼容的类型声明了bar

关于6.5.2.2 6:

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

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

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

是的,C 最初对函数声明很松懈,允许使用空参数列表声明函数,如果我没记错的话,所有参数都使用提升的类型传递。后来支持更严格和更精确的声明,并且编写规则以允许旧代码继续工作。

请注意,有关函数类型兼容性的规则与函数的声明有关,但与调用无关。

当编译器正在分析函数调用时,6.5.2.2 中的规则用于准备调用。这些规则说,根据在调用点可见的函数声明以各种方式处理参数。 (从技术上讲,指向表示被调用函数的表达式的类型。这通常是函数名,但也可以是指向函数的指针,包括由强制转换表达式计算的函数。)

有关兼容性的规则向您保证,如果您使用与实际函数定义的类型兼容的类型调用函数,则该调用具有已定义的行为。

【讨论】:

    猜你喜欢
    • 2019-09-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-03-02
    • 1970-01-01
    相关资源
    最近更新 更多