函数声明不是原型


158

我有一个我创建的图书馆

mylib.c:

#include <mylib.h>
int
testlib() {
    printf("Hello world\n");
    return (0);
}

mylib.h:

#include <stdio.h>
extern int testlib();

在我的程序中,我尝试调用此库函数:

myprogram.c:

#include <mylib.h>

int
main (int argc, char *argv[]) {
    testlib();
    return (0);
}

当我尝试编译该程序时,出现以下错误:

在myprogram.c中包含的文件中:1
mylib.h:2警告:函数声明不是原型

我正在使用: gcc (GCC) 3.4.5 20051201 (Red Hat 3.4.5-2)

我的问题是,声明函数原型的正确方法是什么?


1
从mylib.h中的声明中删除extern,尤其是在编写纯C程序时,在那里不需要extern声明。
Ryan Ahearn

Answers:


333

在C int foo()和中int foo(void)是不同的功能。int foo()接受任意数量的参数,而int foo(void)接受0个参数。在C ++中,它们含义相同。我建议您void在没有参数的情况下保持一致。

如果您有一个变量a,它extern int a;是一种告诉编译器该a符号可能存在​​于其他翻译单元中的一种方法(C编译器表示源文件),请在链接时间之前将其解析。另一方面,作为函数名称的符号无论如何都在链接时解析。在功能的存储类说明的含义(externstatic)只影响其知名度和extern是默认的,所以extern实际上是不必要的。

我建议删除extern,它是多余的,通常被省略。


9
(void) 在C中使用以指示函数不接受任何参数。在C ++中,除非特别需要将代码同时编译为C和C ++,否则请使用()
基思·汤普森

49

快速答案:更改int testlib()int testlib(void)指定该函数不带参数。

根据定义,原型是一个函数声明,它指定函数参数的类型。

非原型函数声明,例如

int foo();

是一种旧式声明,未指定参数的数量或类型。(在1989年ANSI C标准之前,这是该语言中可用的唯一一种函数声明。)您可以使用任意数量的参数调用这样的函数,并且编译器不需要抱怨-但是,如果调用与定义不一致,您的程序具有未定义的行为。

对于采用一个或多个参数的函数,可以在声明中指定每个参数的类型:

int bar(int x, double y);

没有参数的函数是一种特殊情况。从逻辑上讲,使用空括号可以指定一个参数,但该语法已用于旧式函数声明,因此ANSI C委员会发明了一种使用void关键字的新语法:

int foo(void); /* foo takes no arguments */

函数定义(包括函数实际执行的代码)还提供了一个声明。您的情况类似于:

int testlib()
{
    /* code that implements testlib */
}

这为提供了非原型声明testlib。作为定义,它告诉编译器testlib没有参数,但是作为声明,它仅告诉编译器testlib采用一些未指定但固定数量和类型的参数。

如果更改()(void)声明,将成为原型。

原型的优势在于,如果您不小心调用testlib了一个或多个参数,则编译器将诊断出该错误。

(C ++的规则略有不同。C++没有老式的函数声明,并且空括号特别意味着函数不带参数。C++支持(void)与C保持一致的语法。但是除非您特别需要将代码编译为C和C ++,您应该()在C ++中使用,在C中使用(void)语法。)


By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.