7
votes

Prévenir la récursive c #include

Je comprends grosement les règles avec ce que #include le prétraiteur C , mais je ne comprends pas complètement. À l'heure actuelle, j'ai deux fichiers d'en-tête, bouge.h et board.h que tous les deux typé leur type respectif (déménagement et planche). Dans les deux fichiers d'en-tête, je dois référencer le type défini dans l'autre fichier d'en-tête.

en ce moment j'ai #include "bouger.h" à bord.h et #include "board.h" en mouvement.h. Lorsque je compile cependant, GCC se retourne et me donne une longue (ce qui ressemble à l'infini récursif) message d'erreur se retournant entre Move.h et Board.h.

Comment incluez-moi ces fichiers pour que je ne puisse pas y inclure de manière indéfinie?


2 commentaires

Notez que dans un monde idéal, vous évitez les dépendances circulaires comme celle-ci. Ce n'est certainement pas toujours possible et parfois, ils peuvent être très utiles, mais chaque fois que vous créez une dépendance circulaire, vous devriez prendre un moment pour y penser et justifier son existence à vous-même.


@Greg D - Je vous ai pris conseil et j'ai créé un autre fichier appelé type.h où je fais tout mon # définir et typée. J'inclus que dans les deux dossiers, et tout est bon!


7 Réponses :


14
votes

Vous devez examiner , vous avez créé des boucles infinies d'inclure, les déclarations avant sont la solution appropriée.

Voici un exemple: P>

Move. h p> xxx pré>

board.h p> xxx pré>

main.c p> xxx pré> Note: strong> Chaque fois que vous créez un "conseil", vous devrez faire quelque chose comme ceci (il y a quelques façons, voici un exemple): P>

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 */


4 commentaires

Cela ressemble à une très bonne solution, malheureusement, je ne pouvais pas le faire fonctionner (j'ai besoin de regarder #Ifndef et de la façon dont cela fonctionne plus pour bien comprendre cela). Merci pour la réponse cependant.


Quand vous dites "N'a pas travaillé", que voulez-vous dire? En outre, vos types de déménagement et de carte se réfèrent-ils mutuellement ou sont les types utilisés dans les deux fichiers d'en-tête mais pas nécessairement dans les définitions de la structure? (Bouchon sans scrupule: voir aussi ma réponse pour certains pointeurs.)


Oui, veuillez préciser la façon dont il "n'a pas fonctionné", ce code (moins la fonction principale) devrait fonctionner à peu près.


Ni mon déménagement ni mon conseil ne sont composés l'un des autres, j'ai juste besoin du type défini pour certaines méthodes qui prennent une carte et un déménagement. Quand je dis "ça n'a pas fonctionné", cela m'a donné une erreur étrange sur quelque chose de méthodes précédemment définies ailleurs. J'ai essayé quelques modifications sur ce que vous avez proposé, mais je ne pouvais pas obtenir d'entre eux de travailler. Ne pas être une traînée, mais je suis content de la solution que j'ai maintenant pour avoir les TypeDefs dans un fichier d'en-tête séparé (Greg d'Ised).



0
votes

Vous devez en avoir un d'abord. Faire une caisse avancée dans l'une d'entre elles et que celui-ci pour par exemple xxx pré>

pourrait faire partie du fichier. P>

et p>

   typedef struct {…} board;


3 commentaires

Vous ne pouvez pas tester si une structure existe à l'aide du pré-processeur. Si vous impliquez, il devrait également faire une macro nommée, vous devriez aussi préciser.


Vous ne pouvez pas tester les typdefs avec le pré-processeur non plus ... vous auriez besoin d'ajouter littéralement quelque chose comme #define carte quelque part.


HMM .. L'ancien compilateur C Microsoft l'a permis de le permettre, que ce soit, je me demande si je pouvais même trouver une référence à cela. Eh bien, peu importe - beaucoup d'autres ont donné de bonnes réponses.



2
votes

Comme: xxx

de cette façon board.h peut être compilé sans dépendance sur move.h et vous pouvez inclure < code> board.h à partir de move.h pour créer son contenu disponible là-bas.


0 commentaires

3
votes

Inclure les gardes feront partie de la solution à ce problème.

Exemple de Wikipedia: P>

#ifndef GRANDFATHER_H
#define GRANDFATHER_H

struct bar;
struct foo {
    int member;
};

#endif


0 commentaires

0
votes

de K & R Le langage de programmation C (p 91 "Inclusion conditionnelle" dans ma copie), avec quelques modifications pour vous: xxx

et le même pour bouger.h < P> De cette manière, une fois qu'un en-tête a été inclus une fois, il ne sera plus inclus, car le nom 'board_h' a déjà été défini pour le pré-processeur.


2 commentaires

Les macros commençant par un double soulignement sont réservés, vous ne devriez pas les utiliser. De plus, un soulignement suivi d'une lettre majuscule est également réservé.


@Évan - corrigé ce qui précède, merci pour le commentaire. Je pensais que mon commentaire d'édition apparaîtrait ci-dessus mais apparemment pas!



2
votes

Tout d'abord, vous semblez manquer Inclure les gardes dans votre .h Fichiers, vous y incluez donc de manière récursive. C'est mauvais.

Deuxièmement, vous pouvez faire une déclaration en avant. Dans move.h : xxx

in board.h : xxx

Notez que si vous devez déclarer struct Move Move et Carte de structure Objets (plutôt que sur le pointeur sur l'un d'entre eux) dans les fichiers, cette méthode ne sera pas travail. En effet, l'un des types est un type au moment de l'analyse de l'un des fichiers ( struct déplacer dans l'exemple ci-dessus).

Donc, si vous devez utiliser les types dans les fichiers, vous devrez séparer les définitions de type: disposez de fichiers d'en-tête qui définissent struct bouge et carte de structure , et rien d'autre (quelque chose comme mon exemple ci-dessus), puis utilisez un autre fichier d'en-tête qui fait référence à la fois struct déplacer et carte de structure .

Bien sûr, Vous ne pouvez pas avoir struct déplacer contenir un tableau struct et carte de structure contient un struct déplacer en même temps -C'est une récursion infinie et les tailles des structures seront également infinies!


0 commentaires

0
votes

Les dépendances circulaires sont une douleur dans le cul et devraient être éliminées partout où elles sont réalisables. En plus des suggestions de déclaration à terme indiquées jusqu'à présent (les alokes sont le meilleur exemple), j'aimerais lancer une autre suggestion dans les travaux: rompre la dépendance mutuelle entre la carte et le déplacement en introduisant un troisième type (appelez-le de la barre d'appelage de l'illustration; Je suis sûr que vous pouvez trouver un nom moins sucky):

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


0 commentaires