使用不兼容类型调用的没有原型的函数

Function without prototype called with non-compatible type

我阅读了标准 N1570 部分 6.5.2.2 Function calls 并且对包含原型的函数类型的特殊含义感到困惑。准确地说 6.5.2.2(p6)

If the function is defined with a type that does not include a prototype, and the types of the arguments after promotion are not compatible with those of the parameters after promotion, the behavior is undefined, except for the following cases:

— one promoted type is a signed integer type, the other promoted type is the corresponding unsigned integer type, and the value is representable in both types;

— both types are pointers to qualified or unqualified versions of a character type or void.

6.5.2.2(p7)提供了调用原型函数的规则:

If the expression that denotes the called function has a type that does include a prototype, the arguments are implicitly converted, as if by assignment, to the types of the corresponding parameters, taking the type of each parameter to be the unqualified version of its declared type.

考虑以下示例:

struct test_arg{
    int a;
};

void test_no_prototype(const struct test_arg a){ }

void test_with_prototype(const struct test_arg a);

void test_with_prototype(const struct test_arg a){ }

int main(){
    struct test_arg test = {.a = 42};
    test_no_prototype(test);   //1 UB?
    test_with_prototype(test); //2 Fine?
}

我认为 1 是 UB,因为 test_no_prototype 不包含原型并且 test 具有 struct test_arg 的非限定版本,但参数的类型为 const struct test_arg由于资格不同,与 struct test_arg 不兼容。

我认为 2 很好,因为 test_with_prototype 包括原型和来自 6.5.16.1(p1) 的简单赋值约束允许从同一结构的非限定版本赋值给限定结构类型的变量。

这看起来很奇怪,现在我无法想象为什么我们以不同的方式对待有原型和没有原型的函数。可能我对规则的理解不正确...如果是这样你能解释一下它的意思吗?

术语原型 并不意味着在其定义之前的函数声明。它的意思是一个声明其参数类型的函数的声明(C 2018 6.2.1 2)。

test_no_prototype 有一个原型,因为 void test_no_prototype(const struct test_arg a){ } 声明了它的参数类型,const struct test_arg.

没有原型的声明示例是 void test_no_prototype();。这是一种旧的声明方式,不应在新代码中使用。