[C]Problème d'inclusions imbriquées

Problème d'inclusions imbriquées [C] - C - Programmation

Marsh Posté le 13-08-2006 à 23:37:54    

Bonsoir,
 
j'ai deux headers (pour simplifier...) définis comme ça (je n'ai mis que les parties intéressantes):
 

Code :
  1. #ifndef _LAYOUT_H
  2. #define _LAYOUT_H
  3. #include "point.h"
  4. #include "plane.h"
  5. #include "scene.h"
  6. typedef struct
  7. {
  8. Plane  plane;
  9. Plane  scrollable;
  10. Point  refresh;
  11. void  *memory;
  12. } Layout;
  13. void  Layout_DrawScene(Layout *this, Scene *scene, Point *position);
  14. #endif /* _LAYOUT_H */


 
et le deuxième, qui inclut le premier:
 

Code :
  1. #ifndef _SCENE_H
  2. #define _SCENE_H
  3. #include "layout.h"
  4. #include "character.h"
  5. #include "level.h"
  6. typedef struct
  7. {
  8. Layout  screen;
  9. Level  level;
  10. Character player;
  11. } Scene;
  12. #endif /* _SCENE_H */


 
Mais ça ne compile pas, car les deux headers s'incluent l'un l'autre (j'ai déja vu la réponse quelquepart mais je n'arrive pas à remettre la main dessus) :sweat:

Reply

Marsh Posté le 13-08-2006 à 23:37:54   

Reply

Marsh Posté le 14-08-2006 à 08:10:51    

finalement je m'en suis sorti en remplaçant:

Code :
  1. #include "point.h"
  2. #include "plane.h"
  3. #include "scene.h"
  4. typedef struct
  5. {
  6. Plane  plane;
  7. Plane  scrollable;
  8. Point  refresh;
  9. void  *memory;
  10. } Layout;
  11. void  Layout_DrawScene(Layout *this, Scene *scene, Point *position);


 
par
 

Code :
  1. #include "point.h"
  2. #include "plane.h"
  3. struct sScene;
  4. typedef struct
  5. {
  6. Plane  plane;
  7. Plane  scrollable;
  8. Point  refresh;
  9. void  *memory;
  10. } Layout;
  11. void  Layout_DrawScene(Layout *this, struct sScene *scene, Point *position);


 
Si j'ai bien compris, c'est une définition incomplete de la structure, pour pouvoir utiliser un pointeur sur celle-ci sans devoir en donner la définition complète (ce qui permet d'éviter le #include "scene.h" ).
 
Maintenant, est-ce qu'il existe un moyen pour que le prototype

Code :
  1. void  Layout_DrawScene(Layout *this, struct sScene *scene, Point *position);

devienne

Code :
  1. void  Layout_DrawScene(Layout *this, Scene *scene, Point *position);

?


Message édité par b4u le 14-08-2006 à 08:13:56
Reply

Marsh Posté le 14-08-2006 à 09:25:05    

bah voilà, ça s'appelle une forward declaration.

Reply

Marsh Posté le 14-08-2006 à 12:46:31    

oui
sinon j'aimerai bien arriver à ça:

Code :
  1. #include "point.h"
  2. #include "plane.h"
  3. Scene; /* je veux manipuler le type Scene, plutot que struct sScene */
  4. typedef struct
  5. {
  6. Plane  plane;
  7. Plane  scrollable;
  8. Point  refresh;
  9. void  *memory;
  10. } Layout;
  11. void  Layout_DrawScene(Layout *this, Scene *scene, Point *position); /* comme ça j'ai un prototype cohérent avec le reste de l'interface */


mais c'est quoi la bonne syntaxe?


Message édité par b4u le 14-08-2006 à 12:53:24
Reply

Marsh Posté le 14-08-2006 à 13:08:19    

avec un typedef ?
 
struct Scene;
typedef struct Scene Scene;
 
pour l'histoire des includes, imagine qu'au final tout dois etre dans un seul fichier, donc tu ne peux pas inclure l'un avant l'autre et vice-versa, ca n'a pas de sens et en plus tu mets des 'includes gardes' donc ca veut dire que tu ne comprend pas ce que tu ecris

Reply

Marsh Posté le 14-08-2006 à 13:42:56    

si justement, les "includes gardés" protègent contre les multiples inclusions, ce qui permet d'inclure un header dès qu'on veut manipuler les types qu'il définit (ce que je fais toujours, pour des raisons de lisibilités). Un code lisible est plus maintenable, si tu met tout dans un seul fichier tu sera le seul (et encore) à pouvoir faire évoluer ton code...
 
struct Scene;
typedef struct Scene Scene;
 
ok mais je voulais justement éviter de définir Scene en dehors du header qui lui est dédié

Message cité 1 fois
Message édité par b4u le 14-08-2006 à 13:45:25
Reply

Marsh Posté le 14-08-2006 à 14:48:43    

b4u a écrit :

si justement, les "includes gardés" protègent contre les multiples inclusions, ce qui permet d'inclure un header dès qu'on veut manipuler les types qu'il définit (ce que je fais toujours, pour des raisons de lisibilités).


 
je parlais pas de ca, si tu mets des includes gardes dans 2 fichiers qui s'inclusent mutuellement, il y a comme un probleme de comprehension sur la precompilation
 

Citation :

Un code lisible est plus maintenable, si tu met tout dans un seul fichier tu sera le seul (et encore) à pouvoir faire évoluer ton code...


 
quand j'ai dit de tout mettre dans un seul fichier ? j'ai dit qu'apres la precompilation un seul le contenu du .c et des .h inclus se retrouve dans un seul fichier qui correspond au flux textuel de l'unité de traduction, si tu raisonne comme ca tu peux comprendre pourquoi ca n'a aucun sens que 2 fichiers sinclusent mutuellement, avec les includes gardes l'un des 2 includes est ignoré et sans ca part dans un dévellopement d'include "infinie" (en fait limité à 256 je crois)
 

Citation :

ok mais je voulais justement éviter de définir Scene en dehors du header qui lui est dédié


 
dans ce cas de figure on peut tout mettre dans un meme en-tete

Reply

Marsh Posté le 14-08-2006 à 15:18:51    

je vais reformuler le probleme pour éviter qu'on aie a jouer sur les mots:
quelle est la meilleure façon de structurer les fichiers d'en-tete pour éviter les problemes de compilation liés aux forward declarations, sans bousiller l'interface et la structure du code?
par interface je veux dire: définition d'un unique type de donnée et déclaration de son set de fonction associé, le tout clairement lisible, en un ou plusieurs fichiers .h formant un truc homogène?


Message édité par b4u le 14-08-2006 à 15:22:11
Reply

Marsh Posté le 14-08-2006 à 16:24:20    

tu peux faire comme ca pour scene.h
 

Code :
  1. #ifdef SCENE_FORWARD_DECLARATION
  2. #undef SCENE_FORWARD_DECLARATION
  3. struct Scene;
  4. typedef struct Scene Scene;
  5. #else
  6. #ifndef   SCENE_H
  7. #define  SCENE_H
  8. #include "layout.h"
  9. #include "character.h"
  10. #include "level.h"
  11. struct Scene
  12. {
  13.     Layout        screen;
  14.     Level        level;
  15.     Character    player;
  16. };
  17. #endif    /* SCENE_H */
  18. #endif /* SCENE_FORWARD_DECLARATION */


 
et dans Layout.h
 

Code :
  1. #define SCENE_FORWARD_DECLARATION
  2. #include "scene.h"


 
il y a d'autre facons de faire, tu peux par exemple faire en sorte, toujours à l'aide de directives de precompilations,
que la premiere fois que scene.h est inclus ca ne genere que la forward déclaration

Reply

Marsh Posté le 14-08-2006 à 17:06:46    

ok merci :)
ta solution me fait penser qu'en définissant 2 fichiers .h, un pour la définition du type Scene, l'autre pour le prototype des fonctions le manipulant (pareil pour le type Layout) m'éviterait la forward declaration

Message cité 1 fois
Message édité par b4u le 14-08-2006 à 17:07:42
Reply

Marsh Posté le 14-08-2006 à 17:06:46   

Reply

Marsh Posté le 20-08-2006 à 14:25:03    

b4u a écrit :

ok merci :)
ta solution me fait penser qu'en définissant 2 fichiers .h, un pour la définition du type Scene, l'autre pour le prototype des fonctions le manipulant (pareil pour le type Layout) m'éviterait la forward declaration


 
Ben si le type "Scene" (déjà, il serait bien que tu nommes tes types "t_qqchose" et tes structures "s_qqchose", cela te permettra, plus tard, de moins t'embrouiller avec des identifiants de type et des identifiants de variables) est associé au type "layout", alors un seul header pour les deux serait un plus...
 


---------------
Vous ne pouvez pas apporter la prospérité au pauvre en la retirant au riche.
Reply

Sujets relatifs:

Leave a Replay

Make sure you enter the(*)required information where indicate.HTML code is not allowed