OVH Cloud OVH Cloud

parcourir une structure

65 réponses
Avatar
Julien SCORDIA
Bonjour à tous,

J'ai une structure coucou comprenant des pointeurs. Dans certaines
conditions je cherche à allouer ou à libérer ces pointeurs. Je peux tout
faire à la main sans problème. Mais étant donné qu'un plus ou moins grand
nombre de ces pointeurs existe réellement dans la structure (du fait de
constantes préprocesseurs), j'aimerais ne pas avoir à changer mes fonctions
d'allocation et de libération de cette structure à chaque fois que je
rajoute un pointeur dans la structure ou que je change une constante
préprocesseur (par exemple).
C'est pourquoi j'aimerais pouvoir parcourir les divers pointeurs présents
dans la structure sans avoir à me soucier de leur nom, avec une sorte
d'itérateur. L'idée serait alors de tester le type du pointeur en cours, et
d'en déduire la bonne méthode d'allocation ou libération.
Comment peut-on réaliser cela en C?

Par ailleurs, je travaille sur un projet C depuis un bon moment, le
programme commence à être relativement conséquent (tout est relatif, c'est
un programme d'informatique scientifique: le nombre de lignes en ferait
sans doute sourire plus d'un sur ce forum). Un bon nombre de constantes
préprocesseurs sont bien pratiques (imbrication parfois de trois #ifdef
avec des && et || préprocesseurs), mais peuvent parfois gêner la lisibilité
et le parcours du code (sans le fameux % de vim, cela serait vraiment
laborieux). Que pensent les programmeurs professionnels et expérimentés des
constantes préprocesseur?

Merci d'avance pour vos conseils avisés,

Julien
--
"Allez, Monsieur, allez, et la foi vous viendra." (D'Alembert).

10 réponses

1 2 3 4 5
Avatar
Harpo
Julien SCORDIA wrote:

Bonjour à tous,

J'ai une structure coucou comprenant des pointeurs. Dans certaines
conditions je cherche à allouer ou à libérer ces pointeurs. Je peux
tout faire à la main sans problème. Mais étant donné qu'un plus ou
moins grand nombre de ces pointeurs existe réellement dans la
structure (du fait de constantes préprocesseurs), j'aimerais ne pas
avoir à changer mes fonctions d'allocation et de libération de cette
structure à chaque fois que je rajoute un pointeur dans la structure
ou que je change une constante préprocesseur (par exemple).
C'est pourquoi j'aimerais pouvoir parcourir les divers pointeurs
présents dans la structure sans avoir à me soucier de leur nom, avec
une sorte d'itérateur. L'idée serait alors de tester le type du
pointeur en cours, et d'en déduire la bonne méthode d'allocation ou
libération. Comment peut-on réaliser cela en C?


Cela peut dépendre de l'application.
Une solution qui pourrait convenir à quelque chose d'assez statique
serait de mettre les pointeurs dans un tableau soit placé dans la
structure soit pointé par la structure.
Un 'enum' pourrait permettre de les référencer de manière élégante en
associant un symbole à chaque pointeur et de borner le tableau en
donnant sa taille. Pour savoir si un pointeur du tableau correspond à
de la mémoire allouée, les lettre tous à NULL au départ et lorsque la
mémoire est désallouée par la suite.


Par ailleurs, je travaille sur un projet C depuis un bon moment, le
programme commence à être relativement conséquent (tout est relatif,
c'est un programme d'informatique scientifique: le nombre de lignes en
ferait sans doute sourire plus d'un sur ce forum). Un bon nombre de
constantes préprocesseurs sont bien pratiques (imbrication parfois de
trois #ifdef avec des && et || préprocesseurs), mais peuvent parfois
gêner la lisibilité et le parcours du code (sans le fameux % de vim,
cela serait vraiment laborieux). Que pensent les programmeurs
professionnels et expérimentés des constantes préprocesseur?


Ca gène beaucoup la lisibilité et ce n'est pas esthétique. Elles sont
pourtant bien utiles, il faut dans la mesure du possible les regrouper
dans des .h.

Plutôt que de parsemer le code de choses comme :

#ifdef FOO
foo( ) ;
#else
bar( ) ;
#endif

faire une macro dans un .h :

#ifdef FOO
#define blurb( ) foo( )
#else
#define blurb( ) bar( ) ;
#endif

et dans les fonctions :

blurb( ) ;

Avatar
Marc Boyer
In article <425c3839$0$1258$, Julien SCORDIA wrote:
Bonjour à tous,

J'ai une structure coucou comprenant des pointeurs. Dans certaines
conditions je cherche à allouer ou à libérer ces pointeurs. Je peux tout
faire à la main sans problème. Mais étant donné qu'un plus ou moins grand
nombre de ces pointeurs existe réellement dans la structure (du fait de
constantes préprocesseurs), j'aimerais ne pas avoir à changer mes fonctions
d'allocation et de libération de cette structure à chaque fois que je
rajoute un pointeur dans la structure ou que je change une constante
préprocesseur (par exemple).


Je ne suis pas sur de tout comprendre. Est-ce un truc du genre
typedef struct {
#ifdef OPTION_1
int* popt1;
#endif
double* toujours_la;
#ifdef OPTION_2
char* popt2;
#endif
} Coucou;


C'est pourquoi j'aimerais pouvoir parcourir les divers pointeurs présents
dans la structure sans avoir à me soucier de leur nom, avec une sorte
d'itérateur. L'idée serait alors de tester le type du pointeur en cours, et
d'en déduire la bonne méthode d'allocation ou libération.
Comment peut-on réaliser cela en C?


Ca peut être très casse gueule, mais on peut jouer avec
offsetof, une saloperie du genre (non testé)

#define INFO(X) { offsetof(Coucou, X), sizeof( ((Coucou*)0)->X[0] ) }
#define TAB_SIZE(X) (sizeof(X)/sizeof((X)[0]))

typedef struct {
ptrdiff_t offset;
size_t size;
} InfoCoucouPtr;

InfoCoucouPtr infoCoucouPtr[]= {
INFO(toujours_la)
#ifdef OPTION_1
, INFO(popt1)
#endif
#ifdef OPTION_2
, INFO(popt2)
#endif
};

void allocate_all(Coucou* c){
for(int i=0; i < TAB_SIZE(infoCoucouPtr); i++){
void* adrMemb;
adrMemb= ( (char*)c) + infoCoucouPtr[i].offset; // (1)
*adrMemb= malloc( infoCoucouPtr[i].size );
}
}

(1) Le compilo rale sur le typage de cette ligne, il a peut-etre
raison ;-) Je déreférence un void*, c'est pas beau...
Peut-etre que
memcpy(&adrMem, ( (char*)c) + infoCoucouPtr[i].offset )
serait plus sur.. M'enfin bon, c'est l'idée, ça demande
à etre relu.


M'enfin bon, je suis pas sur que tout cela soit plus maintenable
qu'un simple
void allocate_all(Coucou* c){
#ifdef OPTION_1
c->popt1= malloc(sizeof(c->popt1[0]));
#endif
c->toujours_la= malloc(sizeof(c->toujours_la[0]));
#ifdef OPTION_2
c->popt2= malloc(sizeof(c->popt2[0]));
#endif
} Coucou;

Par ailleurs, je travaille sur un projet C depuis un bon moment, le
programme commence à être relativement conséquent (tout est relatif, c'est
un programme d'informatique scientifique: le nombre de lignes en ferait
sans doute sourire plus d'un sur ce forum). Un bon nombre de constantes
préprocesseurs sont bien pratiques (imbrication parfois de trois #ifdef
avec des && et || préprocesseurs), mais peuvent parfois gêner la lisibilité
et le parcours du code (sans le fameux % de vim, cela serait vraiment
laborieux). Que pensent les programmeurs professionnels et expérimentés des
constantes préprocesseur?


Qu'il vaut mieux les éviter, sauf quand on a une très bonne raison ;-)
Sans connaitre le contexte, difficile de juger si on pouvait éviter.

Marc Boyer
--
Je ne respecte plus le code de la route à vélo depuis une double fracture
due au fait que j'étais le seul à le respecter.

Avatar
Antoine Leca
Julien SCORDIA wrote:
Mais étant donné qu'un plus ou
moins grand nombre de ces pointeurs existe réellement dans la
structure (du fait de constantes préprocesseurs),


Est-ce que tu as comparé la complexité que te génère (et te génèrera,
probablement plus encore) cette géométrie variable, avec l'idée d'avoir tous
les pointeurs (mêmes les inutiles) présents dans la structure, et de
n'allouer ou libérer que les membres utilisés (ce qui revient à remplacer
les symboles du préprocesseur par des variables du programme) ?

Et avec l'idée de passer cette partie-là en C++ ?


j'aimerais ne pas
avoir à changer mes fonctions d'allocation et de libération de cette
structure à chaque fois que je rajoute un pointeur dans la structure
ou que je change une constante préprocesseur (par exemple).


En fait cela va plus loin, tu veux que le code qui génère les allocations et
libérations soit automatiquement écrit quand tu rajoute un membre (contrôlé
par une constante) dans la structure, sans que toi tu n'aies rien à faire.

Tel que tu l'as écrit, cela suppose que quand tu rajoutes un membre, tu
rajoutes aussi le code d'allocation et libération, contrôlé par des #ifdef
de la même constante préprocesseur. Mais en dehors du fait que cela n'est
pas de la dernière lisibilité, il n'y a aucun problème dans une telle
démarche, sauf _peut-être_ des sous-programmes partagés par plusieurs
méthodes d'allocation qui peuvent être inclus sans nécessité (on est dans le
deuxième ordre).


C'est pourquoi j'aimerais pouvoir parcourir les divers pointeurs
présents dans la structure sans avoir à me soucier de leur nom, avec
une sorte d'itérateur. L'idée serait alors de tester le type du
pointeur en cours, et d'en déduire la bonne méthode d'allocation ou
libération.


Cela s'appelle information dynamique de type à l'exécution, RTTI.

Comment peut-on réaliser cela en C?


Nécessite des structures de données complémentaires.
En gros, tu veux faire à l'exécution une partie du travail du compilateur.
Comme tu le sais, le compilateur C n'est pas à ta disposition au moment de
l'exécution, donc tu dois écrire toi-même le code qui correspond à la
gestion de la table des symboles et leurs types, et aussi le code qui est
capable de générer un appel selon les dites informations.
Ce qui nous renvoit à ma remarque préliminaire.

Évidemment, c'est possible en C: n'importe quel compilateur C fait cela, et
la plupart pour ne pas dire la quasi-totalité de ceux-ci sont écrits en C.


Antoine

Avatar
Julien SCORDIA
Marc Boyer wrote:

Je ne suis pas sur de tout comprendre. Est-ce un truc du genre
typedef struct {
#ifdef OPTION_1
int* popt1;
#endif
double* toujours_la;
#ifdef OPTION_2
char* popt2;
#endif
} Coucou;


Oui, c'est bien ça, en emboitant des constantes préprocesseur ensemble, et
avec une trentaine de champs.

C'est pourquoi j'aimerais pouvoir parcourir les divers pointeurs présents
dans la structure sans avoir à me soucier de leur nom, avec une sorte
d'itérateur. L'idée serait alors de tester le type du pointeur en cours,
et d'en déduire la bonne méthode d'allocation ou libération.
Comment peut-on réaliser cela en C?


Ca peut être très casse gueule, mais on peut jouer avec
offsetof, une saloperie du genre (non testé)


Ta solution est intéressante, mais effectivement, ce n'est pas forcément
très lisible (en tout cas pour moi).

serait vraiment laborieux). Que pensent les programmeurs professionnels
et expérimentés des constantes préprocesseur?


Qu'il vaut mieux les éviter, sauf quand on a une très bonne raison ;-)
Sans connaitre le contexte, difficile de juger si on pouvait éviter.


Cela me paraissait plus lisible que d'avoir des if ( var ) classiques
(non?), avec les var en question que j'aurais pu passer en ligne de
commande. La deuxième raison est le temps de calcul: étant donné que
l'application est gourmande (plusieurs minutes pour un calcul), je voulais
accélérer les choses au maximum. Maintenant, il est vrai que ce n'est pas
un if ( var ) qui changerait grand chose.

Si je dois regarder les sources d'un programme C sous Linux pour voir un peu
comment sont traités ce genre de problèmes, lequel me conseillez-vous?

Merci pour vos réponses,

Julien
--
"Allez, Monsieur, allez, et la foi vous viendra." (D'Alembert).


Avatar
Julien SCORDIA
Antoine Leca wrote:

C'est pourquoi j'aimerais pouvoir parcourir les divers pointeurs
présents dans la structure sans avoir à me soucier de leur nom, avec
une sorte d'itérateur. L'idée serait alors de tester le type du
pointeur en cours, et d'en déduire la bonne méthode d'allocation ou
libération.


Cela s'appelle information dynamique de type à l'exécution, RTTI.


J'ai lu un bouquin d'introduction sur le C++. Il m'a semblé y voir beaucoup
de principes intéressants comme celui-ci (polymorphisme, surcharge de
fonctions, etc) mais pour l'instant mon expérience de la programmation en
C++ est nulle. Comme je suis pur autodidacte sur ce plan là, ce n'est pas
immédiat.
Est-il aisé de partir d'un programme C et d'utiliser quelques bribes de C++
là où c'est pratique? (comme ça, je dirais non ;-)) )

Comment peut-on réaliser cela en C?


Nécessite des structures de données complémentaires.


Je renvoie à ma question plus bas, à savoir si tu aurais les sources d'un
programme C sous Linux à me conseiller, qui serait instructif à lire
vis-à-vis des questions que je me pose.

Merci pour tes réponses,

Julien
--
"Allez, Monsieur, allez, et la foi vous viendra." (D'Alembert).


Avatar
Antoine Leca
Julien SCORDIA demanda:
J'ai lu un bouquin d'introduction sur le C++. Il m'a semblé y voir
beaucoup de principes intéressants comme celui-ci (polymorphisme,
surcharge de fonctions, etc) mais pour l'instant mon expérience de la
programmation en C++ est nulle. Comme je suis pur autodidacte sur ce
plan là, ce n'est pas immédiat.


Je ne connais pour ainsi dire rien sur C++, en dehors d'un bouquin de
Stroustrup que j'ai lu il y a 20 ans et qui ne m'a guère plu, et des
inférences que je peux faire de par ma connaissance des autres langages de
programmation et des normes.

Cela étant, greffer une structure de données en C++, ou des E/S avec
iostreams sur un programme C (bien écrit, c'est-à-dire compilant _tel quel_
avec un compilo C++) ne me paraît pas un problème du tout. Mais il y a ici
d'autres contributeurs qui font cela à longueur de journée, et qui ont donc
des avis *motivés* sur la question.


Comme il va bien falloir que je m'y mettes un jour, à la place de « C++ pour
les Nuls », quelqu'un aurait les références d'un bon « C++ pour les
programmeurs C chevronnés » ?


Est-il aisé de partir d'un programme C et d'utiliser quelques bribes
de C++ là où c'est pratique? (comme ça, je dirais non ;-)) )


J'ai cru comprendre que l'avantage de C++ (et dans une moindre mesure Java
et C#), par rapport aux autres langages « orientés objet », c'est justement
la réponse Oui à cette question !



Comment peut-on réaliser cela en C?


Nécessite des structures de données complémentaires.


Je renvoie à ma question plus bas, à savoir si tu aurais les sources
d'un programme C sous Linux à me conseiller, qui serait instructif à
lire vis-à-vis des questions que je me pose.


Désolé, mes idées sur la question se développent en programmes de plusieurs
milliers de lignes (des compilaterus, en fait), ce n'est probablement pas ce
que tu cherches... (et c'est la raison de ma remarque préliminaire;
probablement biaisée, comme tu peux le voir).


Antoine



Avatar
Marc Boyer
In article <425d79d9$0$11718$, Julien SCORDIA wrote:
Marc Boyer wrote:

Je ne suis pas sur de tout comprendre. Est-ce un truc du genre
typedef struct {
#ifdef OPTION_1
int* popt1;
#endif
double* toujours_la;
#ifdef OPTION_2
char* popt2;
#endif
} Coucou;


Oui, c'est bien ça, en emboitant des constantes préprocesseur ensemble, et
avec une trentaine de champs.


Super.

C'est pourquoi j'aimerais pouvoir parcourir les divers pointeurs présents
dans la structure sans avoir à me soucier de leur nom, avec une sorte
d'itérateur. L'idée serait alors de tester le type du pointeur en cours,
et d'en déduire la bonne méthode d'allocation ou libération.
Comment peut-on réaliser cela en C?


Ca peut être très casse gueule, mais on peut jouer avec
offsetof, une saloperie du genre (non testé)


Ta solution est intéressante, mais effectivement, ce n'est pas forcément
très lisible (en tout cas pour moi).


Elle n'est pas non plus lisible pour moi, et je la soupsonne
d'être en l'état buguée. Elle demanderait une analyse plus poussée
que le temps quotidien que je consacre à fclc.

serait vraiment laborieux). Que pensent les programmeurs professionnels
et expérimentés des constantes préprocesseur?


Qu'il vaut mieux les éviter, sauf quand on a une très bonne raison ;-)
Sans connaitre le contexte, difficile de juger si on pouvait éviter.


Cela me paraissait plus lisible que d'avoir des if ( var ) classiques
(non?), avec les var en question que j'aurais pu passer en ligne de
commande. La deuxième raison est le temps de calcul: étant donné que
l'application est gourmande (plusieurs minutes pour un calcul), je voulais
accélérer les choses au maximum. Maintenant, il est vrai que ce n'est pas
un if ( var ) qui changerait grand chose.


Pourquoi les passer en ligne de commande ? Elles peuvent aussi
etre des constantes du programme, et on laisse au compilateur le
soin de couper les branches mortes.

Si on a pas prouvé que la taille des structures est en cause,
je serait tenté d'écrire plutot des choses du genre
if (OPT1){
c->opt1= malloc(...);
}
et puis on regarde ensuite si OPT1 est un paramètre de compilation
ou dynamiquement passé en ligne de commande.

Si je dois regarder les sources d'un programme C sous Linux pour voir un peu
comment sont traités ce genre de problèmes, lequel me conseillez-vous?


stdio.h ?
Non, plus sérieusement, c'est illisible à mon gout ce genre de chose.

Marc Boyer
--
Je ne respecte plus le code de la route à vélo depuis une double fracture
due au fait que j'étais le seul à le respecter.



Avatar
Marc Boyer
Antoine Leca wrote:
Julien SCORDIA demanda:
J'ai lu un bouquin d'introduction sur le C++. Il m'a semblé y voir
beaucoup de principes intéressants comme celui-ci (polymorphisme,
surcharge de fonctions, etc) mais pour l'instant mon expérience de la
programmation en C++ est nulle. Comme je suis pur autodidacte sur ce
plan là, ce n'est pas immédiat.


Je ne connais pour ainsi dire rien sur C++, en dehors d'un bouquin de
Stroustrup que j'ai lu il y a 20 ans et qui ne m'a guère plu, et des
inférences que je peux faire de par ma connaissance des autres langages de
programmation et des normes.


On a ecrit des choses plus lisibles sur C++ que la version des
années 80 du bouquin de Stroustrup.

Comme il va bien falloir que je m'y mettes un jour, à la place de « C++ pour
les Nuls », quelqu'un aurait les références d'un bon « C++ pour les
programmeurs C chevronnés » ?


Faudrait demander sur fclc++.

Marc Boyer
--
Je ne respecte plus le code de la route à vélo depuis une double fracture
due au fait que j'étais le seul à le respecter.


Avatar
Marc Boyer
Julien SCORDIA wrote:
Antoine Leca wrote:

C'est pourquoi j'aimerais pouvoir parcourir les divers pointeurs
présents dans la structure sans avoir à me soucier de leur nom, avec
une sorte d'itérateur. L'idée serait alors de tester le type du
pointeur en cours, et d'en déduire la bonne méthode d'allocation ou
libération.


Cela s'appelle information dynamique de type à l'exécution, RTTI.


J'ai lu un bouquin d'introduction sur le C++. Il m'a semblé y voir beaucoup
de principes intéressants comme celui-ci (polymorphisme, surcharge de
fonctions, etc) mais pour l'instant mon expérience de la programmation en
C++ est nulle. Comme je suis pur autodidacte sur ce plan là, ce n'est pas
immédiat.
Est-il aisé de partir d'un programme C et d'utiliser quelques bribes de C++
là où c'est pratique? (comme ça, je dirais non ;-)) )


Oui et non.
Oui dans le sens ou des milliers de programmeurs font cela
quotidiennement. Non dans le sens où ils ont parfois tendance
à croire que C++ est un C amélioré sans voir que pour
l'utiliser pleinement, cela demande de concevoir les applis un
peu différement.

Un des avantage de C++ face à C dans le contexte que tu présentes
serait qu'en lieu et place de
typedef struct {
int* opt1;
double* val;
} Coucou;
bool init(Coucou* c){
c->opt1= new malloc(sizeof(int)*10);
if (!c->opt) return false; // ou assert(c->opt);
c->val= new malloc(sizeof(val)*50);
if (!c->val) return false; // ou assert(c->val);
return true;
}
void destroy(Coucou* c){
free(c->opt1);
free(c->val);
}

On peut simplement écrire
class Coucou {
vector<int> opt1;
vector<double> val;
};
// Equivalent du init
Coucou();opt1(10), val(50) {};
// L'équivalent du destroy est généré automatiquement

Ou simplement, au prix de l'écriture d'une classe vector_initsize
simple.
class Coucou {
vector_initsize<int,10> opt1;
vector_initsize<double,50> val;
};

Et dans ce cas, même plus besoin du init ou destroy.


Marc Boyer
--
Je ne respecte plus le code de la route à vélo depuis une double fracture
due au fait que j'étais le seul à le respecter.



Avatar
AG
Antoine Leca wrote:

Comme il va bien falloir que je m'y mettes un jour, à la place de « C++ pour
les Nuls », quelqu'un aurait les références d'un bon « C++ pour les
programmeurs C chevronnés » ?


http://www.cmla.ens-cachan.fr/Utilisateurs/dosreis/C++/FAQ/

paragraphe 1.3.3, avec notamment le premier cité.

AG.

1 2 3 4 5