Сталкивается с ошибкой, конфликтующий тип данных, но не может найти никакого конфликта

#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:

  1. Устраните все предупреждения компилятора.
  2. Скомпилируйте со всеми включенными предупреждениями компилятора -Wall -Wextra .
  3. Устраните все предупреждения компилятора.
  4. В опубликованном вами коде отсутствует #endif , возможно, из #ifdef HAVE_DIRENT_H , но я предполагаю, что последняя строка file_utils.h должна быть закрывающей #endif .
  5. Предупреждение, которое я получаю от 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 .