声明和原型的区别

C语句中的声明和原型有什么区别? 在哪些情况下,它们被称为声明和原型?

TL; DR; 所有原型都是声明,但并非所有声明都是原型。

声明是标准中使用的通用术语, 原型更具体。

引用C11 ,章节§6.7

声明指定一组标识符的解释和属性。 […]

从§6.7.6开始,

每个声明符声明一个标识符,并断言当与声明符相同的表单的操作数出现在表达式中时,它指定一个函数或对象,其范围,存储持续时间和声明说明符指示的类型。

另一方面,从章节§6.2.1

[….] 函数原型是声明其参数类型的函数的声明。

所以,一个class轮,原型是更完整的forms(包括参数类型)的声明。


关于“标识符”:章节§6.4.2.1,

标识符是一系列非数字字符(包括下划线_ ,小写和大写拉丁字母以及其他字符)和数字,它们指定6.2.1中描述的一个或多个实体。 […]

在章节§6.2.1中,

标识符可以表示对象; function; 标签或结构,联合或枚举的成员; 一个typedef名称; 标签名称; 宏名; 或宏参数。 [….]

声明引入了一个名称:

 int a; // "a" has type int 

函数声明(也不是原型)只引入函数的名称及其返回类型:

 int f(); // a function call expression "f(x, y, ...)" has type int 

但是,这样的函数声明没有指定哪些参数对函数调用有效; 换句话说,它没有指定function签名 。 这是由函数原型(这是一种声明)完成的:

 int g1(void); // "g1" takes no arguments, "g()" has type int int g2(float, char); // "g2" takes two arguments int g3(int, ...); // "g3" takes at least one argument 

函数原型在函数调用时是否可见会对调用参数产生重要影响:如果没有原型可见,则所有参数都会进行默认参数提升。 相比之下,如果原型可用,则函数参数将转换为相应forms参数的类型(如果参数数量不匹配或任何转换forms不正确,则程序格式错误) 。

为了进一步探索这一点,请注意存在某些“不可能”的组合:如果我们有一个声明int g2(); 和定义int g2(float, char) { return 0; } ,永远不可能只使用声明来调用g2 ,因为forms参数类型不能由默认参数提升产生。 通常建议始终使用原型声明,而不要使用非原型声明。

最后,如果原型以省略号( ... )结尾,则可以使用比参数更多的参数调用原型函数。 使用来获取这些参数要求在调用这样的变量参数函数时可以看到函数原型。

  • 函数声明是声明函数并以;结尾的任何forms的行;

  • 原型是一个函数声明,其中指定了所有类型的参数。

示例,原型函数声明: void func (void);
例如,非原型函数声明: void func ();

非原型函数声明是一个过时的function(6.11.6),可能会从C语言中删除。 因此,您应始终使用原型格式,而不是其他任何东西。

根据C标准(6.2.1识别范围)

  1. …(函数原型是声明其参数类型的函数的声明。)

这是一个原型提供有关函数参数类型的信息。

例如,考虑一下

 void f(); 

 void f( void ); 

第一个声明不是原型,因为没有任何关于函数参数的知识。

第二个声明是一个原型,因为它提供了一个函数参数的类型列表(它是一种特殊的类型列表,该函数没有参数)。