ошибка: конфликтующие типы для 'f' и предыдущего объявления 'f' были здесь - PullRequest
3 голосов
/ 17 февраля 2012

Этот код является просто ситуацией, которую я обнаружил в своем реальном коде, который очень большой, поэтому я даю это. здесь в этом коде структура "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

Я получаю:

test.c:6: error: conflicting types for 'f'
test2.h:1: error: previous declaration of 'f' was here

Я дал полный прототип функции f(). Почему я получаю эту ошибку?

Другое дело, что когда я не включаю заголовочный файл test2.h в test.c и явно объявляю прототип функции в 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

Нет ошибок.

Не могли бы вы объяснить, почему в этот раз я не получаю сообщение об ошибке?

Ответы [ 3 ]

5 голосов
/ 17 февраля 2012

Это не имеет ничего общего с ключевым словом 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 голосов
/ 17 февраля 2012

убрать экстерн из шапки.Когда вы объявляете функцию как внешнюю, вы указываете компилятору, что функция не собирается компилироваться, и любая ссылка на эту функцию будет разрешена в связи.Обычно это объявление выполняется при работе с предварительно скомпилированными библиотеками.

1 голос
/ 17 февраля 2012

В вашем test2.h вы объявили f как extern, поэтому вы получаете ошибку. В test.c в прототипе нет объявления extern.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...