错误:'f'的类型冲突,先前声明的'f'在此处。

3

这段代码只是我在实际代码中发现的一个情况,因为我的实际代码非常大,所以我提供了这个例子。在这段代码中,结构体“struct node”没有被定义,它在另一个C源文件中被定义。

我的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

I get:

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

无错误。

请问为什么这一次我没有收到错误提示?


你使用的GCC版本是什么?使用4.6.1版本时,我在最后一个示例中(原型和定义在同一文件中)也会出现错误 - 无论是否带有“extern”。 - Michael Burr
3个回答

7

这与原型的 extern 关键字无关(尽管不是必需的)。

您需要一个struct node的前向声明:

/* test2.h */

struct node;  // <== this

extern void f(struct node * k);

没有这个前向声明,函数原型内的struct node是该特定函数原型的本地变量。
所以当编译器看到f()的定义时,它还会看到另一个不同的本地声明的struct node,认为您对f()有一个冲突的声明。
参见C99 6.9.1“标识符的作用域”:

对于指定的每个不同实体,标识符仅在称为其范围的程序文本区域内可见(即可以使用)。由相同标识符指定的不同实体具有不同的作用域或位于不同的名称空间中。有四种作用域:函数、文件、块和函数原型(函数原型是声明函数参数类型的函数声明)。

...

如果声明符或类型说明符出现在函数原型的参数声明列表中(不是函数定义的一部分),则标识符具有函数原型范围,在函数声明符的末尾终止。

GCC 4.6.1为我提供了一个很好的警告。
C:\temp\test.c:3:22: warning: 'struct node' declared inside parameter list [enabled by default]
C:\temp\test.c:3:22: warning: its scope is only this definition or declaration, which is probably not what you want [enabled by default]

C++ 使函数原型作用域仅适用于参数名 (C++03 3.3.3),因此如果您将代码编译为 C++,就不会遇到这个问题。


2

将头文件中的extern关键字去掉。 当你将一个函数声明为extern时,你告诉编译器该函数不会被编译,任何对该函数的引用都将在链接中解析。 通常,这种声明是在使用预编译库时进行的。


嘿,我从头文件中删除了extern,但仍然得到相同的错误。另外,错误是由于函数参数**struct node *k 引起的吗?在源代码和头文件中都没有定义struct node **,这是在不同的源代码中定义的。 - priyaranjan
这很奇怪,尝试清理并重新编译。你所描述的不应该导致相同的错误。此外,在使用结构定义时始终要包含它... - stdcall
为什么这很重要?我认为这个答案是不正确的。6.2.2 “如果函数标识符的声明没有存储类说明符,则其链接性的确定方式与使用存储类说明符extern声明相同。如果对象标识符的声明具有文件作用域且没有存储类说明符,则其链接性是外部的。” - Lundin

1
在你的test2.h文件中,你已经将f声明为extern,这就是为什么你会得到错误提示的原因。在test.c文件中,原型中没有extern声明。

嘿,我从头文件中删除了extern,但仍然得到相同的错误。另外,错误是由于函数参数**struct node *k 引起的吗?在源代码和头文件中都没有定义struct node **,这是在不同的源代码中定义的。 - priyaranjan
在这种情况下,您需要将“struct node”声明为extern。 - taskinoor
我需要在哪里声明它,是在test2.h还是test.c中。只需写下声明,我不确定我需要声明什么。 - priyaranjan
这是test2.h文件: extern struct node; void f(struct node * k); - taskinoor
谢谢你的帮助,Taskinoor。但我有一个疑问,如果我不包含头文件test2.h并且在test.c中声明函数原型,我可以编译,但是在结构体struct node方面没有任何声明。 - priyaranjan
显示剩余2条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接