函数声明和函数签名有什么区别?

50
在 C 或 C++ 中,函数声明和函数签名有什么区别?
我了解一些函数声明的知识,但函数签名是全新的概念。为什么要有函数签名这个概念?这两个概念实际上用于什么?
谢谢!

6
在C语言中,严格来说并不存在“函数签名”的概念。在C语言中,根本不需要这个概念。“函数签名”的概念完全是C++的范畴,在C语言中毫无意义。 - AnT stands with Russia
那么在C语言中,一个有意义的答案肯定是“没有”,不是吗? - John McFarlane
5个回答

57

一个函数声明是一个函数的原型(如果编译器在这一点上没有看到原型,它可以来自函数定义)- 它包括返回类型、函数名称和参数类型(在 C 中是可选的)。

函数签名是函数声明的一部分,用于执行重载决议。由于多个函数可能具有相同的名称(即它们被重载了),编译器需要一种确定特定名称的几个可能函数中的哪一个函数调用应解析为的方法。签名是编译器在重载决议中考虑的内容。具体而言,标准将“签名”定义为:

参与重载决议的函数信息:其参数的类型以及,如果该函数是类成员,则该函数本身和声明该成员函数的类中的 cv-qualifiers(如果有)。

请注意,返回类型不是函数签名的一部分。正如标准在一条脚注中所说,“函数签名不包括返回类型,因为返回类型不参与重载决议”。


3
说“函数声明就是原型”并不完全正确。在C++中,这种说法在实践中是正确的,但术语上是错误的,因为在C++中没有“原型”这样的术语。在C中,这种说法是严格错误的,因为在C中函数声明不一定是原型。例如,void foo();是一个函数声明,在C中不引入原型。实际上,这个问题不应该标记为C,因为在C中没有“函数签名”的概念。这纯粹是一个C++的问题,因此答案不应提到任何“原型”。 - AnT stands with Russia
4
请提供引用来源? - Manuel Arwed Schmidt
2
你提到了“签名”,“声明”,“原型”和“定义”,但没有清晰的区分。你能否编辑一下,加上每个术语的具体示例? - Andy Ray

7
标准定义了两个术语:声明和定义。定义是一个暂定的声明。然而,C99和C++03标准的定义略有不同。
来自C++0x草案:
附录C
8.3.5 更改:在C++中,使用空参数列表声明的函数不带任何参数。在C中,空参数列表意味着函数参数的数量和类型未知。
定义:
1.3.11 签名
函数的名称、参数类型列表(8.3.5)以及其所属的类、概念、概念映射或命名空间。如果函数或函数模板是类成员,则其签名还包括函数或函数模板本身的cv限定符(如果有)和ref限定符(如果有)。受约束成员的签名(9.2)包括其模板要求。函数模板的签名还包括其返回类型、模板参数列表和模板要求(如果有)。函数模板特化的签名包括其所特化的模板的签名和模板参数(无论是显式指定还是推导出的)。[注意:签名用作名称管理和链接的基础。--结束注释]

2
谢谢,但我感觉很难理解你想说什么。 - Tim
我知道函数声明,但函数签名对我来说是全新的。拥有函数签名的概念有什么意义?这两个概念实际上用于什么? - Tim
3
@Tim: 1) C语言标准没有定义术语"signature"。它在一般的编程文献中被宽泛使用,通常是与函数声明同义的。请注意,函数声明不一定需要有参数。但是,如果你在定义中使用它们,则需要定义它们。2) 编译器广泛地使用签名,例如为一个标识符提供定义,在C++中选择最佳重载等。 - dirkgently

5

函数签名不包括函数的返回类型或链接类型。

好的,维基百科和我对于是否包含返回类型存在分歧。然而,我知道编译器在决定函数调用是否匹配签名时不使用返回类型。这个之前的StackOverflow问题似乎也同意:返回类型是否是函数签名的一部分?


“存储类”是否表示函数所属的类?拥有函数签名的概念的意义是什么?谢谢! - Tim
@Tim:不是。它们指的是适用的链接。 - dirkgently
我不会太相信维基百科现在的文章。它写得不好。方法签名文章稍微好一点。 - Rob Kennedy
我怀疑我混淆了术语 - 存储类是指变量,而不是函数。我的意思是例如 static 或 extern 关键字所暗示的特征。我已经更新了我的答案。 - Mark Ransom
@Mark Ransom:staticextern 是存储类,它们可以适用于 C 和 C++ 中的函数。 - dirkgently
在C++中,返回类型不是函数签名的一部分,无论维基百科说什么,尽管对于其他语言,返回类型可能是函数签名的一部分(老实说我不知道)。 - Michael Burr

3

请注意,根据标准,参数的顶层const和volatile不是签名的一部分。但有些编译器会出现错误。

例如:

void f(const int, const char* const);

与...具有相同的签名

void f(int, const char*);

-1

函数声明是一个原型。函数签名指示返回类型和参数,这些组成了签名。考虑以下内容:

int foo(int, int);  /* 函数声明 */
/* foo的实现 ** 函数签名 */ int foo(int a, int b){ }

现在,考虑以下情况:程序员被问及foo的函数签名:

  • 它返回int数据类型
  • 两个参数也是int数据类型,分别命名为ab

另一方面,函数原型是为了提示C/C++编译器应该期望什么,如果签名与原型不匹配,编译器将发出错误,上下文为“函数声明错误”或“原型不匹配”。


谢谢!所以函数签名是函数定义的一部分,对应于函数声明? - Tim
@Tim:是的,完全正确。 :) 希望你能理解? - t0mm13b
在C语言中,函数声明可能不是原型:int f();就是一个例子。 - Alok Singhal

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接