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

Som*_*ame 6 c function function-call language-lawyer

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

如果使用不包含原型的类型定义函数,并且升级后的参数类型与升级后的参数类型不兼容,则除以下情况外,行为是不确定的:

—一种提升的类型是有符号整数类型,另一种提升的类型是相应的无符号整数类型,并且值在两种类型中都可以表示;

—两种类型都是指向字符类型或void的合格或不合格版本的指针。

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

如果表示被调用函数的表达式的类型确实包含原型,则将参数隐式转换为相应参数的类型,就像通过赋值一样,将每个参数的类型视为其声明的非限定版本。类型。

考虑以下示例:

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?
}
Run Code Online (Sandbox Code Playgroud)

我认为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)允许将同一结构的非限定版本的合格结构类型的变量赋值的简单赋值约束。

这似乎很奇怪,现在我无法想象为什么我们对带有原型和没有原型的函数进行不同处理的任何原因。可能是我对规则的理解不正确...如果可以,您能解释一下这是什么意思吗?

Eri*_*hil 7

术语原型并不意味着在其定义之前声明功能。这意味着声明一个函数,该函数声明其参数的类型(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();。这是旧的声明样式,不应在新代码中使用。

  • @SomeName:`void foo(void)`声明一个不带参数的函数。这是一个原型:这是一个没有参数的原型(就数学逻辑而言,其中的每个参数都有一个声明的类型-没有参数,因此可以满足“每个参数都有一个类型”)。`void foo()`是没有原型的声明。如果函数不带参数,则应使用`void foo(void)`声明它。不要使用`void foo()`。那是旧语法,您不应在新代码中使用。 (2认同)