宣言和原型差异

时间:2017-05-04 11:25:33

标签: c language-lawyer declaration function-prototypes

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

4 个答案:

答案 0 :(得分:9)

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

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

引用C11,章节§6.7

  

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

来自§6.7.6,

  

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

另一方面,从章节§6.2.1

  

[....] 一个功能   prototype是声明其参数类型的函数声明。

因此,一个班轮,原型是更完整的声明形式(包括参数类型)。

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

  

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

和章节§6.2.1,

  

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

答案 1 :(得分:7)

声明引入了一个名称:

int a;    // "a" has type int

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

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

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

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

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

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

最后,如果原型以省略号(...)结尾,则可以调用带有参数的原型函数而不是参数。使用<stdarg.h>来获取这些参数需要在调用这样的变量参数函数时看到函数原型。

答案 2 :(得分:4)

  • 函数声明是声明函数并以;结尾的任何形式的行。

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

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

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

答案 3 :(得分:0)

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

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

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

考虑例如

void f();

void f( void );

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

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