У меня есть два следующих файла заголовков:

player.h

#ifndef _PLAYER_H_
#define _PLAYER_H_
#include "map.h"

typedef struct{
    char* name;
    int x;
    int y;
    int keyMapping;
    char symbol;
}player;
void move(map map, char* move, player player);
void setKeyMapping(int keyMap, player player);
void initPlr(char* name, int x, int y, player player);
#endif

И map.h

#ifndef _MAP_H_
#define _MAP_H_
#include "player.h"

typedef struct{
    char** levelData;
    int width;
    int height;
}map;
void init(map* map,int height, int width);
void print_map(map map, player player);
void resume(const char *resFrom, map map);
void save(const char *saveTo, map map);

#endif

Когда я запускаю файл make, я получаю следующую ошибку:

player.h:10:11: error: unknown type name ‘map’
 void move(map map, int move, player player);

Я относительно новый программист (то есть на C), и я пришел сюда в надежде, что вы, ребята, поможете мне выяснить, почему файлы заголовков не видят друг друга, хотя я их включил. Я использую компилятор gcc, и я проверил, включены ли оба файла заголовков в их партнерские файлы C.

Я также проверил эти три сообщения:

Включить заголовок в другой файл заголовка

Включить заголовки в файл заголовка?

Следует ли использовать #include в заголовках?

РЕДАКТИРОВАТЬ:

Если я отредактирую файл map.h, как указано выше (я добавил параметр player в print_map и оператор include), компилятор выдает эту ошибку:

player.h:12:11: error: unknown type name ‘map’
 void move(map map, char* move, player player);
2
Steampunkery 13 Апр 2016 в 22:30

2 ответа

Лучший ответ

#include Вставка A.h в B.h и B.h в A.h (круговые #include s) всегда является проблемой. Если вам нужно что-то из B.h в A.h и что-то из A.h в B.h, вам нужно будет найти способ обойтись с форвардными объявлениями.

В вашем случае вы ничего не используете из player.h в map.h. Просто удалите следующую строку из map.h.

#include "player.h"
3
R Sahu 13 Апр 2016 в 19:39

Если вы не можете избежать взаимных ссылок на типы в функциях для двух типов, подумайте, действительно ли они принадлежат двум заголовкам. Может, стоит их в один заголовок поместить? В конце концов, компилятор всегда будет включать оба файла anywy.

В качестве альтернативы рассмотрите возможность использования непрозрачных типов:

При использовании непрозрачных типов вы используете указатели на эти типы в интерфейсах функций. Адаптация вашего кода:

map.h

#ifndef MAP_H_INCLUDED
#define MAP_H_INCLUDED

struct Map;
struct Player;

#include "player.h"

typedef struct Map {
    char** levelData;
    int width;
    int height;
} Map;

void init(struct Map* map,int height, int width);
void print_map(struct Map *map, struct Player *player);
void resume(const char *resFrom, struct Map *map);
void save(const char *saveTo, struct Map *map);

#endif

player.h

#ifndef PLAYER_H_INCLUDED
#define PLAYER_H_INCLUDED

struct Map;
struct Player;

#include "map.h"

typedef struct Player{
    char* name;
    int x;
    int y;
    int keyMapping;
    char symbol;
} Player;

void move(struct Map map, char* move, struct Player *player);
void setKeyMapping(int keyMap, struct Player *player);
void initPlr(char* name, int x, int y, struct Player *player);

#endif

Аргументы теперь являются указателями на карты или указателями на игроков, а не прямыми копиями структур.

Любой файл (или оба файла) можно указать в исходном файле, используя их, и код будет компилироваться с обоими. Также обратите внимание, что я отделил имена typedef от имен переменных. Использование одного и того же имени для обоих рискованно. Использование одного и того же имени для тега и typedef не является проблемой; имена typedef находятся в обычном пространстве имен, но имена тегов находятся в отдельном пространстве имен тегов. (В C ++ практически такой же эффект достигается без явной операции typedef: после объявления struct SomeTag вы можете использовать SomeTag для ссылки на тип.)

0
Jonathan Leffler 14 Апр 2016 в 01:05