Предотвращение рекурсивного C #include

Я примерно понимаю правила с тем, что #include делает с препроцессором C, но я не понимаю это полностью. Прямо сейчас у меня есть два заголовочных файла, Move.h и Board.h что и определение типа их соответствующий тип (Перемещение и Совет). В обоих заголовочных файлах я должен сослаться на тип, определенный в другом заголовочном файле.

Прямо сейчас у меня есть #include "Move.h" в Board.h и #include "Board.h" в Move.h. Когда я компилирую, хотя, gcc зеркальные отражения и дает мне длинное (что похоже бесконечный рекурсивный), зеркальное отражение сообщения об ошибке между Move.h и Board.h.

Как я включаю эти файлы так, чтобы я рекурсивно не включал неограниченно долго?

7
задан Brian Tompsett - 汤莱恩 20 February 2016 в 22:20
поделиться

7 ответов

Вам нужно посмотреть в прямые объявления , вы создали бесконечные петли включенных, передовые декларации являются правильным решением.

Вот пример:

MOVE.H

#ifndef MOVE_H_
#define MOVE_H_

struct board; /* forward declaration */
struct move {
    struct board *m_board; /* note it's a pointer so the compiler doesn't 
                            * need the full definition of struct board yet... 
                            * make sure you set it to something!*/
};
#endif

PORD.H

#ifndef BOARD_H_
#define BOARD_H_

#include "Move.h"
struct board {
    struct move m_move; /* one of the two can be a full definition */
};
#endif

MAIN.C

#include "Board.h"
int main() { ... }

Примечание: Всякий раз, когда вы создаете «доску», вам нужно будет что-то подобное ( Есть несколько способов, вот пример):

struct board *b = malloc(sizeof(struct board));
b->m_move.m_board = b; /* make the move's board point 
                        * to the board it's associated with */
14
ответ дан 6 December 2019 в 08:43
поделиться

Включает охранников будет частью решения этого вопроса.

Пример Wikipedia:

#ifndef GRANDFATHER_H
#define GRANDFATHER_H

struct foo {
    int member;
};

#endif

http://en.wikipedia.org/wiki/include_guard

Другая часть, как отмечена несколькими другими, направлена ​​на пересылку. ( http://en.wikipedia.org/wiki/forward_Reference )

Вы можете частично объявить одну из структур над другим, подобным так:

#ifndef GRANDFATHER_H
#define GRANDFATHER_H

struct bar;
struct foo {
    int member;
};

#endif
3
ответ дан 6 December 2019 в 08:43
поделиться

, как так:

//Board.h
#ifndef BOARD_H
#define BOARD_H
strunct move_t; //forward declaration
typedef struct move_t Move;
//...
#endif //BOARD_H

//Move.h
#ifndef MOVE_H
#define MOVE_H
#include "Move.h"
typedef struct board_t Board;
//...
#endif //MOVE_H

таким образом Board.h может быть скомпилирован без зависимости от MOVE .H , и вы можете включить Board.h из move.h , чтобы сделать его содержание там.

2
ответ дан 6 December 2019 в 08:43
поделиться

Вам нужно иметь один из них первым. Сделайте прямое DECAL в одном из них и имейте, что один для примера

    #ifndef move
    struct move;
    #endif

может быть частью файла POWER.H.

И

    #ifndef board
    struct board;
    #endif

может быть частью файла move.h

, то вы можете добавить их в любой заказ.

Редактировать Как было отмечено в комментариях ... Я предполагал, что использование Typedef Construction следующим образом для структуры доски

   typedef struct {…} board;

, поскольку я никогда не видел никого, используя структуры в C без типов, я сделал это предположение ... возможно Вещи изменились с прошлого года, когда я закодировал в C (Yikies .... Это было как 15 лет назад)

0
ответ дан 6 December 2019 в 08:43
поделиться

От K & R языка программирования C (P 91 "Условное включение" в мою копию), с некоторыми настройками для вас:

#if !defined (BOARD_H)
#define BOARD_H

/* contents of board.h go here */

#endif

и то же самое для move.h

таким образом После того, как заголовок был включен один раз, он не будет включен в комплект снова, так как имя «Board_H» уже определено для препроцессора.

0
ответ дан 6 December 2019 в 08:43
поделиться

Цирусные зависимости являются болью в заднице и должны быть устранены везде, где это возможно. В дополнение к предложениям передней декларации, приведенные до сих пор (Alok, является лучшим примером), я хотел бы бросить еще одно предложение в работы: нарушать взаимную зависимость между доской и переместиться путем введения третьего типа (вызовите его BoardMovAsococ для иллюстрации; Я уверен, что вы можете придумать менее засоснение):

#ifndef H_BOARD_MOVE_ASSOC
#define H_BOARD_MOVE_ASSOC

#include "Move.h"
#include "Board.h"

struct BoardMoveAssoc {
    Move m;
    Board b;
};

...
#endif

по этой схеме, доску и шагом не нужно ничего знать друг о друге; Любые ассоциации между ними управляются типа POWERMOVEASOSOCOC. Точная структура будет зависеть от того, как должны быть связаны движение и доска; E.g., если несколько движений отображаются на одной доске, структура может выглядеть больше похожей на

 struct BoardMoveAssoc {
     Move m[NUM_MOVES] // or Move *m;
     Board b;
 };

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

0
ответ дан 6 December 2019 в 08:43
поделиться

Я предпочитаю следующее решение (требуйте Джанго > = 1,0).

settings.py

INSTALLED_APPS+= ('django.contrib.flatpages',)

urls.py

urlpatterns+= patterns('django.contrib.flatpages.views',
    url(r'^about-us/$', 'flatpage', {'url': '/about-us/'}, name='about'),
    url(r'^license/$', 'flatpage', {'url': '/license/'}, name='license'),
)

В шаблонах

[...]
<a href="{% url about %}"><span>{% trans "About us" %}</span></a>
<a href="{% url license %}"><span>{% trans "Licensing" %}</span></a>
[...]

или в коде

from django.core.urlresolvers import reverse
[...]
reverse('license')
[...]

Это путь вам не нужно использовать django.contrib.flatpages.middleware.FlatpageFallbackMiddleware , и реверс работает как обычно, не записывая столько кода, сколько в других решениях.

Ура.

-121--2178529-

Во-первых, вам не хватает включить охранников в файлы .h , поэтому вы включаете их рекурсивно. Это плохо.

Во-вторых, можно сделать форвардное объявление. В Move.h :

/* Include guard to make sure your header files are idempotent */
#ifndef H_MOVE_
#define H_MOVE_

#include "Board.h"

/* Now you can use struct Board */
struct Move { struct Board *board; };

#endif

В Board.h :

#ifndef H_BOARD_
#define H_BOARD_

struct Move; /* Forward declaration.  YOu can use a pointer to
                struct Move from now on, but the type itself is incomplete,
                so you can't declare an object of the type itself. */
struct Board { struct Move *move; }; /* OK: since move is a pointer */

#endif

Обратите внимание, что если необходимо объявить объекты struct Move и struct Board (а не указывать на один из них) в обоих файлах, этот метод не будет работать. Это связано с тем, что один из типов является неполным типом во время синтаксического анализа одного из файлов ( struct Move в приведенном выше примере).

Таким образом, если необходимо использовать типы в обоих файлах, необходимо выделить определения типов: иметь заголовочные файлы, которые определяют struct Move и struct Board , и ничего другого (что-то подобное моему примеру выше), а затем использовать другой заголовочный файл, который ссылается на struct Move и struct Board .

Конечно, нельзя, чтобы struct Move содержали struct Board и struct Board содержали struct Move одновременно - это будет бесконечная рекурсия, и структура

2
ответ дан 6 December 2019 в 08:43
поделиться
Другие вопросы по тегам:

Похожие вопросы: