Это не имеет ничего общего с ключевым словом 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 ++.