-
函数原型
2025-12-14 04:22:18 2014德国世界杯
函数声明位于函数定义之前,并指定函数的名称、返回类型、存储类和其他属性。 要成为原型,函数声明还必须为函数的参数建立类型和标识符。
语法
declaration:
declaration-specifiers
attribute-seq
选择init-declarator-list选择;
/*
attribute-seq
opt 是特定于Microsoft */
declaration-specifiers:
storage-class-specifier
declaration-specifiers
选择
type-specifier
declaration-specifiers
选择
type-qualifier
declaration-specifiers
选择
init-declarator-list:
init-declarator
init-declarator-list
,
init-declarator
init-declarator:
declarator
declarator
=
initializer
declarator:
pointer
选择direct-declarator
direct-declarator:/* 函数声明符 */
direct-declarator
(
parameter-type-list
) /* 新样式声明符 */
direct-declarator
(
identifier-list
选择) /* 过时样式声明符 */
原型与函数定义具有相同的形式,只是在右括号后立即以分号终止,因此没有正文。 在任一情况下,返回类型都必须与函数定义中指定的返回类型一致。
函数原型具有以下重要用途:
它们为返回类型以外的 int函数建立返回类型。 尽管返回 int 值的函数不需要原型,但建议使用原型。
如果没有完整的原型,则会进行标准转换,但不会尝试使用参数数检查参数的类型或数量。
原型用于在定义这些函数之前初始化指向函数的指针。
参数列表用于检查函数调用中的参数是否与函数定义中的参数匹配。
每个参数的转换类型决定了函数调用在堆栈上放置的参数的解释。 参数和参数之间的类型不匹配可能会导致堆栈上的参数被错误解释。 例如,在 16 位计算机上,如果 16 位指针作为参数传递,然后声明为 long 参数,则堆栈上的前 32 位解释为 long 参数。 此错误不仅会创建 long 参数的问题,还会产生所有后续参数的问题。 可以通过为所有函数声明完整的函数原型来检测此类错误。
原型建立函数的属性。 然后,可以检查函数定义之前的函数调用(或在其他源文件中发生)是否存在参数类型和返回类型不匹配。 例如,如果在原型中指定 static 存储类说明符,则还必须在函数定义中指定 static 存储类。
完整的参数声明(int a)可以与同一声明中的抽象声明符(int)混合使用。 例如,以下声明是合法的:
int add( int a, int );
原型可以同时包含作为参数传递的每个表达式的类型和标识符。 但是,此类标识符仅在声明结束之前处于范围内。 原型还可以反映参数数可变或未传递任何参数的事实。 如果没有此类列表,可能无法显示不匹配,因此编译器无法生成有关它们的诊断消息。 有关类型检查的详细信息,请参阅 参数。
使用编译器选项进行编译 /Za 时,Microsoft C 编译器中的原型范围现在符合 ANSI。 如果在原型中声明或structunion标记,则会在该范围而不是全局范围内输入标记。 例如,使用 /Za ANSI 一致性进行编译时,永远无法调用此函数,而不会收到类型不匹配错误:
void func1( struct S * );
若要更正代码,请在函数原型之前定义或声明 struct 全局 union 范围:
struct S;
void func1( struct S * );
在下方 /Ze,标记仍在全局范围内输入。
另请参阅
函数