函数原型Function Prototypes

函数声明位于函数定义之前,用来指定函数的名称、返回类型、存储类和其他特性。A function declaration precedes the function definition and specifies the name, return type, storage class, and other attributes of a function. 若要作为原型,函数声明还必须为函数的参数确定类型和标识符。To be a prototype, the function declaration must also establish types and identifiers for the function's arguments.

语法Syntax

declarationdeclaration:
declaration-specifiers attribute-seq optinit-declarator-list opt;declaration-specifiers attribute-seq optinit-declarator-list opt;

/* attribute-seq opt 是 Microsoft 专用的 //* *attribute-seq opt is Microsoft Specific */

declaration-specifiersdeclaration-specifiers:
storage-class-specifier declaration-specifiers optstorage-class-specifier declaration-specifiers opt

type-specifier declaration-specifiers opttype-specifier declaration-specifiers opt

type-qualifier declaration-specifiers opttype-qualifier declaration-specifiers opt

init-declarator-listinit-declarator-list:
init-declaratorinit-declarator

init-declarator-list , init-declaratorinit-declarator-list , init-declarator

init-declaratorinit-declarator:
declaratordeclarator

declarator = initializerdeclarator = initializer

declaratordeclarator:
pointer optdirect-declaratorpointer optdirect-declarator

direct-declarator: /* 函数声明符 */direct-declarator: /* A function declarator */
direct-declarator ( parameter-type-list ) /* 新样式声明符 */direct-declarator ( parameter-type-list ) /* New-style declarator */

direct-declarator ( identifier-list opt) /* 旧样式声明符 */direct-declarator ( identifier-list opt) /* Obsolete-style declarator */

原型与函数定义具有相同的形式,只不过前者由紧跟在右括号后的分号结尾,因此没有主体。The prototype has the same form as the function definition, except that it is terminated by a semicolon immediately following the closing parenthesis and therefore has no body. 在任一情况下,返回类型都必须与函数定义中指定的返回类型一致。In either case, the return type must agree with the return type specified in the function definition.

函数原型有下列重要用途:Function prototypes have the following important uses:

  • 它们建立返回除 int 之外的类型的函数的返回类型。They establish the return type for functions that return types other than int. 尽管返回 int 值的函数不需要原型,但仍建议使用原型。Although functions that return int values do not require prototypes, prototypes are recommended.

  • 如果没有完整原型,将进行标准转换,但不会尝试使用形参的数量检查实参的类型或数量。Without complete prototypes, standard conversions are made, but no attempt is made to check the type or number of arguments with the number of parameters.

  • 原型用于在定义函数之前初始化指向函数的指针。Prototypes are used to initialize pointers to functions before those functions are defined.

  • 形参列表用于通过函数定义中的形参来检查函数调用中的实参的对应性。The parameter list is used for checking the correspondence of arguments in the function call with the parameters in the function definition.

    每个形参的转换类型决定函数调用在堆栈上放置的实参的解释。The converted type of each parameter determines the interpretation of the arguments that the function call places on the stack. 自变量和参数的类型不匹配可能导致堆栈上的自变量被错误解释。A type mismatch between an argument and a parameter may cause the arguments on the stack to be misinterpreted. 例如,在 16 位计算机上,如果 16 位指针作为实参传递,然后声明为 long 形参,则堆栈上的前 32 位将解释为 long 形参。For example, on a 16-bit computer, if a 16-bit pointer is passed as an argument, then declared as a long parameter, the first 32 bits on the stack are interpreted as a long parameter. 此错误不仅会导致 long 参数出现问题,而且会导致其后面的所有参数出现问题。This error creates problems not only with the long parameter, but with any parameters that follow it. 您可通过声明所有函数的完整函数原型来检测此类错误。You can detect errors of this kind by declaring complete function prototypes for all functions.

    原型将确定函数的特性,以便能检查位于函数定义前面(或者出现在其他源文件中)的函数调用是否存在参数类型和返回类型不匹配。A prototype establishes the attributes of a function so that calls to the function that precede its definition (or occur in other source files) can be checked for argument-type and return-type mismatches. 例如,如果在原型中指定 static 存储类说明符,则还必须在函数定义中指定 static 存储类。For example, if you specify the static storage-class specifier in a prototype, you must also specify the static storage class in the function definition.

    完整参数声明 (int a) 可以与同一声明中的抽象声明符 (int) 组合在一起。Complete parameter declarations (int a) can be mixed with abstract declarators (int) in the same declaration. 例如,以下声明是合法的:For example, the following declaration is legal:

int add( int a, int );  

原型可同时包含作为参数传递的每个表达式的类型和标识符。The prototype can include both the type of, and an identifier for, each expression that is passed as an argument. 但是,此类标识符的范围只到该声明的末尾。However, such identifiers have scope only until the end of the declaration. 原型也可以反映参数的数量是变量或未传递参数的事实。The prototype can also reflect the fact that the number of arguments is variable, or that no arguments are passed. 如果没有此类列表,则不能显示不匹配项,从而使编译器无法生成有关它们的诊断消息。Without such a list, mismatches may not be revealed, so the compiler cannot generate diagnostic messages concerning them. 有关类型检查的详细信息,请参阅参数See Arguments for more information on type checking.

使用 /Za 编译器选项进行编译时,Microsoft C 编译器中的原型范围现在符合 ANSI。Prototype scope in the Microsoft C compiler is now ANSI-compliant when compiling with the /Za compiler option. 这意味着,如果在原型中声明 struct 或 union 标记,则将在该范围而不是全局范围内输入该标记。This means that if you declare a struct or union tag within a prototype, the tag is entered at that scope rather than at global scope. 例如,为符合 ANSI 而使用 /Za 进行编译时,您绝不可能调用此函数而不遇到类型不匹配错误:For example, when compiling with /Za for ANSI compliance, you can never call this function without getting a type mismatch error:

void func1( struct S * );  

若要更正代码,请在全局范围中函数原型之前定义或声明 struct 或 union:To correct your code, define or declare the struct or union at global scope before the function prototype:

struct S;  
void func1( struct S * );  

在 /Ze 下,仍将在全局范围内输入标记。Under /Ze, the tag is still entered at global scope.

另请参阅See Also

函数Functions