这段代码只是我在实际代码中找到的一个非常大的情况,所以我给出了这个。这里的代码结构“struct node”没有定义它在另一个c源中定义文件。
我的源代码:
/* test.c */
1 #include<stdio.h>
2 #include "test2.h"
3
4 void f(struct node * k)
5 {
6
7 }
我的标题文件:
/* test2.h */
1 extern void f(struct node * k);
当我使用gcc编译此代码以创建目标文件时:
gcc -w -c test.c
我明白了:
test.c:6: error: conflicting types for 'f'
test2.h:1: error: previous declaration of 'f' was here
我已经给出了函数f()
的完整原型。为什么我收到此错误?
另一件事是,当我在 test.c 中不包含头文件 test2.h 并在test.c
中显式声明函数原型时,它编译成功。代码如下:
/* test.c */
1 #include<stdio.h>
2 void f(struct node *k);
3
4 void f(struct node * k)
5 {
6
7 }
gcc -c -w test.c
没有错误。
请您解释为什么这次我没有收到错误?
答案 0 :(得分:5)
这与原型上的extern
关键字无关(尽管没有必要)。
您需要struct node
的前瞻声明:
/* test2.h */
struct node; // <== this
extern void f(struct node * k);
如果没有前向声明,函数原型中的struct node
是 local 到该特定函数原型。
因此,当编译器看到f()
的定义时,它还会看到struct node
的另一个不同的本地声明,并认为您对{{1}有一个冲突的声明}。
见C99 6.9.1“标识符范围”:
对于标识符指定的每个不同实体, 标识符仅在区域内可见(即,可以使用) 程序文本称为其范围。由指定的不同实体 相同的标识符具有不同的范围,或者具有不同的名称 空间。范围有四种:函数,文件,块和 功能原型。 (函数原型是a的声明 声明其参数类型的函数。)
...
如果是声明标识符的声明符或类型说明符 出现在函数的参数声明列表中 标识符具有原型(不是函数定义的一部分) 函数原型范围,它终止于函数的末尾 说明符。
GCC 4.6.1为我提供了一个很好的警告:
f()
C ++使函数原型范围仅适用于参数名称(C ++ 03 3.3.3),因此如果将代码编译为C ++,则不会看到此问题。
答案 1 :(得分:2)
从标题中删除extern。 当您将函数声明为外部函数时,您将指导编译器不会编译该函数,并且将在链接中解析对该函数的任何引用。 通常,此声明在使用预编译库时完成。
答案 2 :(得分:1)
在test2.h中,您已将f
声明为extern
,这就是您收到错误的原因。在test.c中,原型中没有extern
声明。