【问题标题】:Why is it legal to change function prototype after its definition?为什么定义后更改函数原型是合法的?
【发布时间】:2021-08-16 02:05:03
【问题描述】:
int test();
int test(){
 return 5;
}
int test(int in);

int main() {
   return test();
}

我知道一个函数可以有多个(和类似的)声明,并且只有一个定义。

我的问题与自己定义后的声明有关。编译器是否选择它遇到的最后一个原型作为真正的原型?即使它来自父亲的完整定义?

这不编译错误说: error: too few arguments to function 'test'

【问题讨论】:

  • int test() 不是原型。这是一个 K&R 风格的声明。
  • int test(); 正在声明一个带有未定义参数的函数。因此它将与任何其他 int test(...) 声明“兼容”。但是尝试给它不同的参数列表,它就不行了。
  • int test(); 不是原型。这是一个无原型的声明——一个为向后兼容而存在的结构,与int test(void) prototype 不同。如果你从不使用int test();,你的生活会更简单。除非您尝试与 pre-ansi C 向后兼容,否则永远不需要它。
  • 这是2个int test(){ ... }int test(int in);相互冲突,而不是int test();
  • 这个问题所证明的混乱是一个强烈的理由不断提醒人们不要写int main()

标签: c function-declaration function-prototypes


【解决方案1】:

您的示例代码中有三个test 声明:

  1. int test(); 是一个不是原型1 或定义2 的声明。
  2. int test() { return 5; } 是一个声明,它是函数的定义。
  3. int test(int in); 是作为函数原型的声明。

简单的声明,数字 1,是不完整的。3 它没有说明是否有任何参数或其类型是什么。此声明可以由声明 2 或声明 3 完成,但不能同时由两者完成。如果 2 和 3 都存在,编译器应该会给出警告或错误消息。4

具体来说,回答您的问题“为什么在定义后更改函数原型是合法的?”:在不完整的声明之后,您可以通过添加更多信息来更改函数类型的已知信息,使用旧式定义或现代原型。除了添加更多信息之外,您无法进行更改。5(原型或定义后,函数类型已完成,您无法进行任何更改。)

声明 2 匹配旧式函数定义,其中参数定义在结束 ) 之后和开始 { 之前:

return-type name-of-function(names-of-parameters) declarations of parameters { body-of-function }

例如:

int test(n, x)
int n;
double x;
{
    …
}

当这种风格的定义中没有参数时,表示该函数不带参数。注意区别:

  • int test(); 没有说参数是什么,甚至没有说有多少。
  • int test() { return 5; } 表示没有参数。

如您所见,这些是兼容的:不说明有多少参数与说没有参数是兼容的。6

声明 3 是一种现代声明,它表示只有一个参数,类型为 int。与 2 一样,声明 1 和 3 是兼容的:不说明有多少参数或它们可能具有哪些类型与说有一个 int 类型的参数是兼容的。

但是,声明 2 和 3 不兼容:

  • 声明 2 说没有参数。
  • 声明 3 说只有一个参数。

脚注

1 函数原型声明其参数的类型。由于() 为空,因此没有声明参数类型。 (由于 C 的历史,函数声明中的() 意味着没有提及参数,(void) 是一个原型,表示没有参数。)

2 函数定义包括函数体,大括号括起来的复合语句包含函数执行的代码。

3这里使用的“不完整”是普通英语的意思,而不是 C 标准适用于对象类型的意思。

4 这是 C 2018 6.7 4 中的约束所要求的:“同一范围内引用同一对象或函数的所有声明都应指定兼容的类型。”

5 可能会有一些细微的变化。例如,可以在参数中添加或删除诸如 const 之类的限定符,尽管出于兼容性目的这不会更改函数类型。

6函数类型兼容性的具体规则在C 2018 6.7.6.3 15.

【讨论】:

    【解决方案2】:

    这是不符合 C 标准的无效代码。

    根据 C 标准(6.7.6.3 函数声明符(包括原型))

    1. 要兼容两种函数类型...如果一种类型有参数 类型列表,另一种类型由 a 指定 包含 a 的函数定义(可能为空) 标识符列表,两者应在参数数量上一致,并且 每个原型参数的类型应与类型兼容 这是应用默认参数提升的结果 对应标识符的类型....

    即在呈现的代码中声明了两个不兼容的函数。

    【讨论】:

      猜你喜欢
      • 2012-03-05
      • 1970-01-01
      • 2013-06-24
      • 2011-01-21
      • 2017-05-31
      • 2013-01-10
      • 1970-01-01
      • 2015-03-16
      • 1970-01-01
      相关资源
      最近更新 更多