[C ADA] visibilité des données

visibilité des données [C ADA] - C - Programmation

Marsh Posté le 23-12-2004 à 07:28:42    

Originaire de l'ADA et débutant en C, je voudrais transposer le principe des visibilités de l'ADA vers le C.
 
Ex:  
J'ai 3 modules nommés "un", "deux" et "trois".  
Le module "un" lance les modules "deux" et "trois".
Les modules "deux" et "trois" utilisent des ressources communes.
 
Voici comment je donne la vue sur ces données à mes deux modules:
 
-en ADA: je crée un modules nommé "données" et je donne la visibilité à ce fichier dans les modules "deux" et "trois" par la clause "with données"
 
-en C: 1) je déclare les donnees dans le module "deux" et je les déclare en "extern" dans le module "trois"
2)je déclare les données dans le module au dessus nommé "un", et je les déclare en extern dans mes modules "deux" et "trois"
 
Problème: dans le 1) des dépendances transversales sont crées. Si je n'ai plus besoin de ma donnée dans le module "un", il faut que je supprime sa déclaration, et en plus que j'aille dans le module "deux" pour supprimer la clause extern.
dans le 2) je déclare des données qui ne seront utilisées que dans les modules en dessous et pas au niveau ou elles sont déclarées. Par contre il n'y a plus de lien transversal et le principe d'arborescence et d'indépendance des branches est respecté.
 
Voila mes soucis, certes plus philosophiques que techniques, merci de m'éclairer la dessus, et désolé si j'ai réinventé l'eau tiède.

Reply

Marsh Posté le 23-12-2004 à 07:28:42   

Reply

Marsh Posté le 23-12-2004 à 09:12:28    

Ton package spec, on va dire que ça devient le fichier d'include, et le package body, c'est le fichier C.
 
Note que le compilateur C ne connait pas le concept de fichier d'include (en effet, celui-ci est inclus par le pré-processeur).
 
Bon, ton problème, tu proposes de le résoudre avec:
 

Code :
  1. un.h:
  2.   // rien
  3. un.c:
  4. #include "deux.h"
  5. static int donnée_un;
  6. deux.h:
  7. extern int donnée_deux;
  8. deux.c:
  9. int donnée_deux;


 
Bah c'est très bien. Mais ce n'est pas parce qu'il n'y a plus de dépendance entre le module 1 et le module 2 qu'il faille enlever la déclaration externe de donnée_2, ainsi que sa définition (qui est dans deux.c). En conception logicielle, ça ne sert à rien de travailler le code pour qu'il corresponde exactement à la réalité actuelle. Si tu as des données partagées qui ne sont pas réellement utilisées ailleurs, ce n'est pas nécessaire de les supprimer si tu penses qu'elle te reserviront potentiellement un jour.

Reply

Marsh Posté le 23-12-2004 à 09:53:32    

Merci pour ta réponse mais cela ne me convient pas sinon je n'aurais pas posé la question.
Le fait de garder des déclarations données qui seront potentiellement utilisées ne me satisfait pas. Certaines normes (DO ou autres) ne tolèrent pas d'avoir des déclarations de variables qui ne sont pas utilisées.
Pour faire marcher un code, c bien joli; pour faire un code propre et dans le respect des normes c tout autre chose.
Moi, ce que je veux savoir, c comment faire autrement que ma solution 1 du langage C, s'il y en a une. Et la je m'adresse plus particulièrement à des codeurs qui réalisent de gros codes en appliquant des règles vérifiant des contraintes aéronautiques, automobiles ou medicales.
Toute solution ou piste pour remplacer ma proposition 1 est la bienvenue.

Reply

Marsh Posté le 23-12-2004 à 10:26:15    

pgaranx a écrit :

Originaire de l'ADA et débutant en C, je voudrais transposer le principe des visibilités de l'ADA vers le C.
 
Ex:  
J'ai 3 modules nommés "un", "deux" et "trois".  
Le module "un" lance les modules "deux" et "trois".
Les modules "deux" et "trois" utilisent des ressources communes.


C'est quoi des ressources communes ? Des variables globales? Beark! Pas de ça en C professionel. Les données ne sont jamais visibles. Tout passe par des pointeurs sur des structures incomplètes (très proches d'un void *, mais typées). Pour accéder aux données, on utilise des accesseurs en ecriture ou en lecture. Ca permet un contrôle des acces.
 
http://mapage.noos.fr/emdel/tad.htm
 
Au fait, c'est 'Ada' et non 'ADA'... C'est un nom propre comme 'Pascal')


Message édité par Emmanuel Delahaye le 23-12-2004 à 13:12:31

---------------
Des infos sur la programmation et le langage C: http://www.bien-programmer.fr Pas de Wi-Fi à la maison : http://www.cpl-france.org/
Reply

Marsh Posté le 23-12-2004 à 12:03:56    

Globales, oui et non. Elles sont globales à partir du module un et pour ceux qui sont en dessous, c'est ce que je veux.
Mais elles sont opaques pour les modules au dessus et au meme niveau que le module un.
Le reproche que l'on peut faire, c que ces données sont déclarées à certain niveau et utilisées seulement un niveau en dessous.
 
Il semble clairement de convenance (dans certaines grosses boites meme), de déclarer une variable dans un fichier c et de balancer des extern dans tous les autres fichiers qui s'en serve, juste histoire que ça compile. Moi ça me gene.
 

Reply

Marsh Posté le 23-12-2004 à 12:53:40    

Euh, j'ai deux questions.  
1. C'est quoi un module ?  
 
2. Et d'autre part, à partir du moment où il y a une dépendance entre 2 modules (m1 utilise m2), pars-tu du principe que tous les symboles de m2 doivent être visibles depuis m1 ?
 
Si c'est le cas, alors la solution à base de extern est tout à fait compréhensible, puisqu'elle fait "apparaitre" tous les symboles publics (par opposition à ceux qui ne sont pas exposés par le module) afin d'être accessibles aux modules utilisateurs.
 

Reply

Marsh Posté le 23-12-2004 à 13:17:44    

pgaranx a écrit :

Globales, oui et non. Elles sont globales à partir du module un et pour ceux qui sont en dessous, c'est ce que je veux.
Mais elles sont opaques pour les modules au dessus et au meme niveau que le module un.
Le reproche que l'on peut faire, c que ces données sont déclarées à certain niveau et utilisées seulement un niveau en dessous.
 
Il semble clairement de convenance (dans certaines grosses boites meme), de déclarer une variable dans un fichier c et de balancer des extern dans tous les autres fichiers qui s'en serve, juste histoire que ça compile. Moi ça me gene.


Moi aussi!
 
Tu peux réduire la visibiité en fournissant le header contenant les externes uniquement au niveau qui en a besoin, et pas aux niveaux supérieurs, mais rien n'empêche un barbare de mettre sa propre déclaration extern (en se trompant de type, de préférence!) dans n'importe quel source, car techniquement, la variable est accessible de partout.
 
C'est pourquoi j'insiste sur l'encapsulation de type ADT (TAD).
 
Les variables sont tout simplement invisibles, sauf du module d'implémentation qui contient la définition de la structure complète. Ca fait le ménage...
 
 


---------------
Des infos sur la programmation et le langage C: http://www.bien-programmer.fr Pas de Wi-Fi à la maison : http://www.cpl-france.org/
Reply

Marsh Posté le 23-12-2004 à 13:19:05    

Si ADA a été inventé, c'est justement parceque les autres langages de l'époque dont le C ne permettait pas d'avoir des données ultra typé comme en ADA avec un super cloisenement. Il ne faut donc pas demander à ce langage ce pourquoi il n'a pas été conçu. Je pense cependant qu'il doit y avoir des moyens de faire de l'édition de lien entre des modules en C et des modules en ADA.

Reply

Marsh Posté le 23-12-2004 à 16:07:12    

Bon ben le TAD, j'avoue que je comprends pas du tout, mais ....
 
si je déclare une structure comme celle ci :
 
struct données {
   type données_1
   type données_2
...
}
struct données lire_données, *ecrire_données;
ecrire_donnees = &lire_données;
 
Et maintenant dans mes deux fichiers (deux et trois) je viens lire ou ecrire mes variables avec :
lire_données.données_1 ou ecrire_données.données_1
 
Est ce que cela te parait un peu plus sécurisé que l'utilisation de déclarations "classiques" ?
 
Si oui, meme question que précédemment: par principe de symétrie, ne serait il pas plus "joli" de déclarer cette structure dans le fichier appelant ("un" ), de manière à avoir une distribution des données arborescente.
J'ai bien peur que tu me répondes: et si un barbare met une clause extern, il aura une visibilité sur la structure.
Je te préviens, si je le chope, je lui coupe les mains.

Reply

Marsh Posté le 23-12-2004 à 18:00:41    

pgaranx a écrit :

Bon ben le TAD, j'avoue que je comprends pas du tout, mais ....


Aie! C'est le B.A. BA de la programmation orienté objet! Comme tu le sais, le C n'est pas OO, mais il permet de séparer physiquement interface et implémentation. C'est vrai et c'est bien connu pour les fonctions (prototype séparé), mais, ce que l'on sait moins, c'est que c'est vrai aussi pour les données, moyennant quelques précautions.
 
L'idée est définir une structure incomplète 'publique' qui est placé dans l'interface aka 'en-tête' ou 'header' (.h),  


/* montype.h */
#ifndef H_MONTYPE
#define H_MONTYPE
 
struct montype;
 
#endif /* guard */


alors que la structure complète est placée dans le fichier d'implémentation:


/* montype.c */
#include "montype.h"
 
struct montype
{
   type data_a;
   type data_b;
};


Pour le moment, tout ce qu'on peut faire de l'extérieur est la création d'un pointeur du même type:


/* main.c */
#include "montype.h"
 
int main (void)
{
   struct montype *p;
 
   return 0;
}


En effet, comme le type est incomplet, on ne connait pas sa taille, donc on ne peut créer un instance par une définition statique ou automatique.

  struct montype data;


Alors comment faire ? Tout simplement en définissant une paire de fonctions assurant le rôle de créateur / destructeur.


struct montype *montype_create(void);
void montype_delete (struct montype *this);


Ces prototypes vont évidemment dans l'interface. Dans l'implémentation, on détaille les fonctions :  


#include <stdlib.h>
 
struct montype *montype_create(void)
{
   /* creation dynamique de l'objet */
   struct montype *this = malloc (sizeof *this);
 
   if (this != NULL)
   {
      /* mise a 0 des elements (portable et auto-maintenable) */
      static const struct montype z = {0};
      *this = z;
   }
   return this;
}
 
void montype_delete (struct montype *this)
{
   if (this != NULL)
   {
      /* suppression de l'objet dynamique */
      free (this);
   }
}
 


Voici comment on utilise ces fonctions:


/* main.c */
#include "montype.h"
 
int main (void)
{
   struct montype *p = montype_create();
 
   if (p != NULL)
   {
      /* ... */
 
      montype_delete(p), p = NULL;
   }
   return 0;
}


Tu peux essayer d'accéder aux données p->data_a, p->data_b, tu verras que c'est impossible. La protection est absolue.
 
Je te laisse écrire les accesseurs...


Message édité par Emmanuel Delahaye le 23-12-2004 à 18:01:29

---------------
Des infos sur la programmation et le langage C: http://www.bien-programmer.fr Pas de Wi-Fi à la maison : http://www.cpl-france.org/
Reply

Sujets relatifs:

Leave a Replay

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