#c
#c
Вопрос:
Я объявил функцию в file_utils.h и определил его в file_utils.c Во время компиляции выдает ошибку конфликтующего типа.
File_utils.h
#ifndef FILE_UTILS_H
#define FILE_UTILS_H
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
#include <stdbool.h>
#include <sys/types.h>
#ifdef HAVE_DIRENT_H
#include <dirent.h>
#define NAMLEN(dirent) strlen((dirent)->d_name)
#else
#define dirent direct
#define NAMLEN(dirent) ((dirent)->d_namlen)
#ifdef HAVE_SYS_NDIR_H
#include <sys/ndir.h>
#endif
#ifdef HAVE_SYS_DIR_H
#include <sys/dir.h>
#endif
#ifdef HAVE_NDIR_H
#include <ndir.h>
#endif
#endif
bool is_relative_path(struct dirent *ent);
File_utils.c
#include "file_utils.h"
#include <stdbool.h>
#include <dirent.h>
bool is_relative_path(struct dirent *ent){
return (strcmp(ent->d_name, ".") == 0 || strcmp(ent->d_name, "..") == 0);
}
Ошибка:
abhiram@abhiram-Lenovo-G50-70:~/libpostal-master/src$ gcc -DLIBPOSTAL_DATA_DIR='"$//home/abhiram/libpostal-master/data"' -o main main.c libpostal.c file_utils.c json_encode.c string_utils.c -std=c99 -w
file_utils.c:45:6: error: conflicting types for ‘is_relative_path’
bool is_relative_path(struct dirent *ent){
^
In file included from file_utils.c:1:0:
file_utils.h:59:6: note: previous declaration of ‘is_relative_path’ was here
bool is_relative_path(struct dirent *ent);
^
Я включил обе библиотеки dirent.h и stdbool.h.
Комментарии:
1. В вашем последнем комментарии говорится о файле «dirent.h», в то время как вся остальная часть вопроса, а также выходные данные отладки говорят о «file_utils.c» и «file_utils.h». Возможно, в этих 3 файлах есть противоречивые определения того, что такое
struct dirent
?2. @GuntherSchulz Я включил все директивы о dirent, содержащиеся в коде, другой структуры, определенной мной как таковой, не существует.
3. @Abhiram проверьте мой полный ответ ниже
Ответ №1:
- Устраните все предупреждения компилятора.
- Скомпилируйте со всеми включенными предупреждениями компилятора
-Wall -Wextra
. - Устраните все предупреждения компилятора.
- В опубликованном вами коде отсутствует
#endif
, возможно, из#ifdef HAVE_DIRENT_H
, но я предполагаю, что последняя строкаfile_utils.h
должна быть закрывающей#endif
. - Предупреждение, которое я получаю от gcc, заключается в следующем:
предупреждение: ‘struct direct’ объявлен внутри списка параметров
предупреждение: его область действия — это только это определение или объявление, которое, вероятно, не то, что вы хотите
Это самое важное предупреждение.
Определение структуры допустимо только внутри списка параметров функции. Пример:
void other_f(
struct B a // this will forward declare struct B
// scope of this variable is _only_ inside function parameter list
); // here struct B get's out of scope!
struct B b; // will error, there is no struct B here
// struct B was declared inside function parameter list
// you can't use it anywhere else
Ответом на вашу проблему может быть следующий пример:
void f(struct A);
struct A;
void f(struct A); // error conflicting types for 'f'
struct A
Будет объявлено (я называю это «автоматически объявленным») внутри списка параметров функции void f( <here> )
при первом использовании. Объявление структуры будет видно только внутри списка параметров. Таким образом, это похоже на псевдокод:
{
struct A; // type only valid inside `{` `}` braces
void f(struct A a); // imagine this symbol is visible outside `{` `}`
}
ie. struct A
не отображается за пределами {
}
.
Затем вы объявляете другой struct A
:
struct A;
void f(struct A a);
Но этот struct A
тип отличается от другого struct A
. Поскольку это другое, struct A
функция f
отличается, компилятор выдает ошибку.
Нет, рассмотрите ваш заголовок:
#define dirent direct
...
bool is_relative_path(struct dirent *ent);
Я не знаю, direct
это опечатка или нет. Но вам нужно переадресовать объявление struct direct
, чтобы прямое объявление struct direct было видно за пределами списка параметров функции is_relative_path
function.
struct direct;
#define dirent direct
...
// or here:
struct dirent;
bool is_relative_path(struct dirent *ent);
Ответ №2:
Похоже, что ваша проблема заключается в порядке включения файла, если "File_utils.c"
и / или отсутствует определение HAVE_DIRENT_H
.
В данном порядке включения "file_utils.h"
понятия не имеет, что такое struct dirent
, поскольку (предположительно HAVE_DIRENT_H
) определено внутри <dirent.h>
. Если это НЕ так, просто убедитесь, что HAVE_DIRENT_H
определено перед включением "file_utils.h"
Конечный результат как есть в коде заключается в том, что в "file_utils.h"
, bool is_relative_path(struct dirent *ent)
фактически рассматривается как bool is_relative_path(some_pointer_to_an_unknown_struct_type ent)
, в то время как "file_utils.c"
сигнатура функции воспринимается как bool is_relative_path(a_pointer_to_a_struct_type_i_definately_know_about ent)
.
Таким образом, два файла не согласуются с сигнатурой функции.
Редактировать
@n.m. прав в том, что "file_utils.h"
по существу видит отличное определение struct dirent
и что нельзя объявлять тип внутри списка параметров функции.
TLDR
Отредактируйте File_utils.c, чтобы определить HAVE_DIRENT_H
и / или #include <dirent.h>
перед #include "file_utils.h"
, чтобы оба "file_utils.h"
и "file_utils.c"
видели общую сигнатуру функции для bool is_relative_path(struct dirent *ent)
Комментарии:
1. добавление
HAVE_DIRENT_H
в file_utils.c не сработало, оно выдает ту же ошибку и#include<dirent.h>
перед"file_utils.h"
выдает предыдущую ошибку, а также выдает ошибкуfile_utils.c: In function ‘is_relative_path’: file_utils.c:70:20: error: dereferencing pointer to incomplete type return (strcmp(ent->d_name, ".") == 0 || strcmp(ent->d_name, "..") == 0); ^ file_utils.c:70:53: error: dereferencing pointer to incomplete type return (strcmp(ent->d_name, ".") == 0 || strcmp(ent->d_name, "..") == 0); ^
2. @Abhiram, «разыменование указателя на неполный тип» обычно происходит, когда вы неправильно указываете тип назначения указателя, а затем пытаетесь разыменовать указатель на этот тип с ошибкой. Внимательно проверьте на наличие опечаток при
struct dirent
использовании
Ответ №3:
Похоже, что объявление bool is_relative_path(struct dirent *ent);
находится ПОСЛЕ #endif
объявления препроцессора (включает защитные устройства). Это означает, что включение этого файла заголовка в два разных файла приведет к двум объявлениям. Взгляните на это: https://en.wikipedia.org/wiki/Include_guard чтобы получить более подробную информацию
Это должно исправить это:
#ifndef FILE_UTILS_H
#define FILE_UTILS_H
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
#include <stdbool.h>
#include <sys/types.h>
#ifdef HAVE_DIRENT_H
#include <dirent.h>
#define NAMLEN(dirent) strlen((dirent)->d_name)
#else
#define dirent direct
#define NAMLEN(dirent) ((dirent)->d_namlen)
#ifdef HAVE_SYS_NDIR_H
#include <sys/ndir.h>
#endif
#ifdef HAVE_SYS_DIR_H
#include <sys/dir.h>
#endif
#ifdef HAVE_NDIR_H
#include <ndir.h>
#endif
// moved the declaration between the #ifndef #endif block
bool is_relative_path(struct dirent *ent);
#endif
Комментарии:
1. Но у вас может быть столько повторяющихся одинаковых объявлений, сколько вы хотите. У вас отсутствует
#endif
.2. @KamilCuk прав в том, что повторные объявления разрешены. Проблема НЕ В этом. Смотрите мой полный ответ выше
3. Понял вашу точку зрения. Я пропустил это. Звучит как плохая идея иметь ` #include <dirent.h>` в файле c, верно?
4. Я попытался переместить объявление, как вы предложили, оно по-прежнему выдает ту же ошибку конфликтующего типа
Ответ №4:
Вы не можете объявить тип внутри списка параметров функции. Это то, что происходит при использовании File_utils.h у вас есть объявление is_relative_path
без предварительного объявления stuct dirent
.
Либо #include <dirent.h>
в File_utils.h (рекомендуется) или добавьте объявление
struct dirent;
где-то в нем выше is_relative_path
.