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)
允许将同一结构的非限定版本的合格结构类型的变量赋值的简单赋值约束。
这似乎很奇怪,现在我无法想象为什么我们对带有原型和没有原型的函数进行不同处理的任何原因。可能是我对规则的理解不正确...如果可以,您能解释一下这是什么意思吗?
术语原型并不意味着在其定义之前声明功能。这意味着声明一个函数,该函数声明其参数的类型(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();
。这是旧的声明样式,不应在新代码中使用。