GNT sans publicité, site mobile, fonctionnalitées exclusives...

Empêcher l'accès aux données d'un struct

Le
TSalm
Bonjour,

Voici une petite question de noob motivé.
Venant du monde de la POO, j'ai démarrer un pgm en C avec un struct qui
contient les données, et des fonctions qui s'appliquent à ce struct.
Par exemple, dans le header, j'ai ceci :
/* - HEADER - */
typedef struct
(int data1
,int data2
) MonStruct;

void MonStruct_create();
void MonStruct_free(MonStruct*);
void MonStruct_fait_quelquechose(MonStruct*,int data);
/* -- */

Mon problème est que les données("data1" et "data2") de "MonStruct"
pourraient être, par inadvertance (ou plutôt feignantise ;-) ),
directement modifiées sans passer par les fonctions.
Est-il possible de pouvoir déclarer les données "data1" et "data2" dans
l'implémentation (le fichier ".c"), de façon à ce que l'utilisation de
MonStruct ne puisse se faire qu'en passant par les fonctions ?

D'avance merci pour vos avis ou éventuelles remarques.
-TSalm
Lire les 36 réponses

Vidéos High-Tech et Jeu Vidéo
Téléchargements
Vos réponses Page 1 / 8
Gagnez chaque mois un abonnement Premium avec GNT : Inscrivez-vous !
Trier par : date / pertinence
Pascal J. Bourguignon
Le #24203071
TSalm
Bonjour,

Voici une petite question de noob motivé.
Venant du monde de la POO, j'ai démarrer un pgm en C avec un struct
qui contient les données, et des fonctions qui s'appliquent à ce
struct.
Par exemple, dans le header, j'ai ceci :
/* ---------- HEADER ---------- */
typedef struct
(int data1
,int data2
) MonStruct;

void MonStruct_create();
void MonStruct_free(MonStruct*);
void MonStruct_fait_quelquechose(MonStruct*,int data);
/* -------------------------- */

Mon problème est que les données("data1" et "data2") de "MonStruct"
pourraient être, par inadvertance (ou plutôt feignantise ;-) ),
directement modifiées sans passer par les fonctions.
Est-il possible de pouvoir déclarer les données "data1" et "data2"
dans l'implémentation (le fichier ".c"), de façon à ce que
l'utilisation de MonStruct ne puisse se faire qu'en passant par les
fonctions ?

D'avance merci pour vos avis ou éventuelles remarques.



Non. Et oui.


/* ---------- MonObjet.h ---------- */
#ifndef MonObjet_h
#define MonObjet_h

typedef void* MonObjet;

extern MonObjet MonObjet_new();
extern void MonObjet_free(MonObjet this);
extern void MonObjet_fait_quelquechose(MonObjet this,int data);

#endif
/* -------------------------------- */


/* ---------- MonObjet.c ---------- */
#include
typedef struct {
int slot1;
int slot2;
} MonObjet_implementation;


MonObjet MonObjet_new()
{
MonObjet_implementation* that=malloc(sizeof(*that));
if(that){
that->slot1=0;
that->slot2=0;
return((MonObjet)that);
}else{
perror("malloc");
exit(1);
}
}


void MonObjet_free(MonObjet this)
{
MonObjet_implementation* that=(MonObjet_implementation*)this;
/* (appeler ici les methodes free des slots si nécessaire) */
free(that);
}

void MonObjet_fait_quelquechose(MonObjet this,int data)
MonObjet_implementation* that=(MonObjet_implementation*)this;
that->slot1=that->slot2;
that->slot2Úta;
}

/* -------------------------------- */
--
__Pascal Bourguignon__ http://www.informatimago.com/
A bad day in () is better than a good day in {}.
Pascal J. Bourguignon
Le #24203411
TSalm
Merci pour cette réponse tout à fait intéressante.
Par contre, ça oblige à faire un cast au début de chaques
fonctions. Est-ce que ça ne risque pas de ralentir l'exécution de
cette fonction ?



Non.


Autre question, pourquoi utiliser "extern" pour les prototypes de
fonctions ? Est-ce une recommandation pour garder une compatibilité
avec certains compilateurs ?



Je ne suis pas au courrant des derniers standard. Je ne vois pas
pourquoi ils renonceraient à la déclaration extern.


--
__Pascal Bourguignon__ http://www.informatimago.com/
A bad day in () is better than a good day in {}.
TSalm
Le #24203401
Voici une petite question de noob motivé.
Venant du monde de la POO, j'ai démarrer un pgm en C avec un struct
qui contient les données, et des fonctions qui s'appliquent à ce
struct.
Par exemple, dans le header, j'ai ceci :
/* ---------- HEADER ---------- */
typedef struct
(int data1
,int data2
) MonStruct;

void MonStruct_create();
void MonStruct_free(MonStruct*);
void MonStruct_fait_quelquechose(MonStruct*,int data);
/* -------------------------- */

Mon problème est que les données("data1" et "data2") de "MonStruct"
pourraient être, par inadvertance (ou plutôt feignantise ;-) ),
directement modifiées sans passer par les fonctions.
Est-il possible de pouvoir déclarer les données "data1" et "data2"
dans l'implémentation (le fichier ".c"), de façon à ce que
l'utilisation de MonStruct ne puisse se faire qu'en passant par les
fonctions ?

D'avance merci pour vos avis ou éventuelles remarques.



Non. Et oui.


/* ---------- MonObjet.h ---------- */
#ifndef MonObjet_h
#define MonObjet_h

typedef void* MonObjet;

extern MonObjet MonObjet_new();
extern void MonObjet_free(MonObjet this);
extern void MonObjet_fait_quelquechose(MonObjet this,int data);

#endif
/* -------------------------------- */


/* ---------- MonObjet.c ---------- */
#include
typedef struct {
int slot1;
int slot2;
} MonObjet_implementation;


MonObjet MonObjet_new()
{
MonObjet_implementation* that=malloc(sizeof(*that));
if(that){
that->slot1=0;
that->slot2=0;
return((MonObjet)that);
}else{
perror("malloc");
exit(1);
}
}


void MonObjet_free(MonObjet this)
{
MonObjet_implementation* that=(MonObjet_implementation*)this;
/* (appeler ici les methodes free des slots si nécessaire) */
free(that);
}

void MonObjet_fait_quelquechose(MonObjet this,int data)
MonObjet_implementation* that=(MonObjet_implementation*)this;
that->slot1=that->slot2;
that->slot2Úta;
}

/* -------------------------------- */



Merci pour cette réponse tout à fait intéressante.
Par contre, ça oblige à faire un cast au début de chaques fonctions.
Est-ce que ça ne risque pas de ralentir l'exécution de cette fonction ?
Autre question, pourquoi utiliser "extern" pour les prototypes de
fonctions ? Est-ce une recommandation pour garder une compatibilité avec
certains compilateurs ?
ps: Je viens de voir que je m'étais planté dans la déclaration de mon
struct, dsl.
Marc
Le #24203391
"Pascal J. Bourguignon" wrote:

typedef void* MonObjet;

extern MonObjet MonObjet_new();
extern void MonObjet_free(MonObjet this);
extern void MonObjet_fait_quelquechose(MonObjet this,int data);



Y a-t-il une raison particulière de passer par un void*? On peut tout à
fait déclarer une struct sans la définir sur place, et ça n'empêche pas
d'utiliser des pointeurs vers elle.
Samuel DEVULDER
Le #24203381
Le 28/01/2012 17:39, TSalm a écrit :
Bonjour,

Mon problème est que les données("data1" et "data2") de "MonStruct"
pourraient être, par inadvertance (ou plutôt feignantise ;-) ),
directement modifiées sans passer par les fonctions.
Est-il possible de pouvoir déclarer les données "data1" et "data2" dans
l'implémentation (le fichier ".c"), de façon à ce que l'utilisation de
MonStruct ne puisse se faire qu'en passant par les fonctions ?



Tu peux te débrouiller en rendant opaque le contenu de MonStruct pour
l'utilisateur en utilisant la compilation conditionnelle. Je te propose
de faire ainsi (en gros)


Monstruct.h:
----8<-----------------------------------------8<---------------------
#ifndef MONSTRUCT_H
#define MONSTRUCT_H

typedef struct MonStruct_internal {
int data1;
int data2;
}

typedef struct
#ifdef MONSTRUCT_INTERNAL
MonStruct_internal
#else
{const char opaque[sizeof(struct MonStruct_internal)];}
#endif
Monstruct;

#endif //MONSTRUCT_H
MonStruct;

extern Monstruct* MonStruct_create(int data1);
extern void MonStruct_free(MonStruct*);
extern void MonStruct_fait_quelquechose(MonStruct*,int data);
----8<-----------------------------------------8<---------------------

Monstruct.c:
----8<-----------------------------------------8<---------------------
#include <les machins standards>

#define MONSTRUCT_INTERNAL
#include "Monstruct.h"
Monstruct* MonStruct_create(int data1) {
Monstruct* resultat = malloc(sizeof(Monstruct));
if(resultat==NULL) {... traitement "plus de mémoire"...}
resultat->data1 = data1; // accès aux chose interne
resultat->data2 = 0;
}
void MonStruct_fait_quelquechose(MonStruct* ptr,int data) {
ptr->data2 += data - ptr->data1;
}
----8<-----------------------------------------8<---------------------

utilisateur.c:
----8<-----------------------------------------8<---------------------
#include <les machins standard>
#include "Monstruct.h"

void code(Monstruct *p) {
p->opaque = ???? // en fait on ne sait rien de ce
// qu'il y a dans "opaque" Il faut
// passer par les fonctions Monstruct_*()
MonStruct_fait_quelquechose(p, 42);
}
----8<-----------------------------------------8<---------------------

Bon c'est l'idée. Tu peux varier à l'infini ou presque.

sam.
Publicité
Suivre les réponses
Poster une réponse
Anonyme