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;
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
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;
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.
Il est tout a fait possible de manipuler des struct machin * sans connaitre struct machin, et ca evite de faire des casts tout moches.
Tu peux parfaitement faire
struct machin;
struct machin * new_machin(...);
dans ton .h
et n'avoir la definition effective de struct machin que dans le .c...
Tu as seulement besoin d'avoir la definition d'une structure pour avoir sa taille, et acceder a ses champs. Pour le reste, genre pour travailler avec des pointeurs, pas besoin de la definition.
Ca evite l'usage intempestif de void *, qui enleve au C le peu de typage dont il dispose encore.
(et ca marche tres bien avec un typedef si on a envie. Ca peut sans probleme etre un
dans le .h. L'absence de definition de struct machin ailleurs que dans un .c n'est pas plus perturbante que ca.
In article <87ty3f93m2.fsf@kuiper.lan.informatimago.com>,
Pascal J. Bourguignon <pjb@informatimago.com> wrote:
TSalm <tsalm@free.fr> writes:
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;
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.
Il est tout a fait possible de manipuler des struct machin * sans connaitre
struct machin, et ca evite de faire des casts tout moches.
Tu peux parfaitement faire
struct machin;
struct machin *
new_machin(...);
dans ton .h
et n'avoir la definition effective de struct machin que dans le .c...
Tu as seulement besoin d'avoir la definition d'une structure pour avoir
sa taille, et acceder a ses champs. Pour le reste, genre pour travailler
avec des pointeurs, pas besoin de la definition.
Ca evite l'usage intempestif de void *, qui enleve au C le peu de typage
dont il dispose encore.
(et ca marche tres bien avec un typedef si on a envie. Ca peut sans probleme
etre un
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;
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.
Il est tout a fait possible de manipuler des struct machin * sans connaitre struct machin, et ca evite de faire des casts tout moches.
Tu peux parfaitement faire
struct machin;
struct machin * new_machin(...);
dans ton .h
et n'avoir la definition effective de struct machin que dans le .c...
Tu as seulement besoin d'avoir la definition d'une structure pour avoir sa taille, et acceder a ses champs. Pour le reste, genre pour travailler avec des pointeurs, pas besoin de la definition.
Ca evite l'usage intempestif de void *, qui enleve au C le peu de typage dont il dispose encore.
(et ca marche tres bien avec un typedef si on a envie. Ca peut sans probleme etre un
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.
Pour ce que j'en sais, il faut finir par définir ces structures. C'est ce que l'on veut éviter.
De toutes facons, je ne vois pas comment tu pourras les manipuler sans les definir d'une facon ou d'une autre. Que tu les definisses en bas niveau en jouant avec tes void * ou en ecrivant une struct, ca ne changera rien.
Ce qu'on veut, c'est que la definition ne soit pas dans les fichiers visibles par l'utilisateur. Dans l'implementation de la bibliotheque, il n'y a pas le choix. Et si l'utilisateur est VRAIMENT acharne, il peut definir ses propres structures et acceder aux champs.
In article <87lior8yh8.fsf@kuiper.lan.informatimago.com>,
Pascal J. Bourguignon <pjb@informatimago.com> wrote:
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.
Pour ce que j'en sais, il faut finir par définir ces structures. C'est
ce que l'on veut éviter.
De toutes facons, je ne vois pas comment tu pourras les manipuler sans les
definir d'une facon ou d'une autre. Que tu les definisses en bas niveau
en jouant avec tes void * ou en ecrivant une struct, ca ne changera rien.
Ce qu'on veut, c'est que la definition ne soit pas dans les fichiers visibles
par l'utilisateur. Dans l'implementation de la bibliotheque, il n'y a pas
le choix. Et si l'utilisateur est VRAIMENT acharne, il peut definir ses
propres structures et acceder aux champs.
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.
Pour ce que j'en sais, il faut finir par définir ces structures. C'est ce que l'on veut éviter.
De toutes facons, je ne vois pas comment tu pourras les manipuler sans les definir d'une facon ou d'une autre. Que tu les definisses en bas niveau en jouant avec tes void * ou en ecrivant une struct, ca ne changera rien.
Ce qu'on veut, c'est que la definition ne soit pas dans les fichiers visibles par l'utilisateur. Dans l'implementation de la bibliotheque, il n'y a pas le choix. Et si l'utilisateur est VRAIMENT acharne, il peut definir ses propres structures et acceder aux champs.
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.
Pour ce que j'en sais, il faut finir par définir ces structures. C'est ce que l'on veut éviter.
On la définit dans le fichier .c, qui n'est pas visible par l'utilisateur.
Enfin en tout cas j'ai l'impression que "pimpl" est la réponse à la question d'origine.
*soupir*. Non, pimpl (dit aussi "compiler firewall") est la reponse a une AUTRE question: pimpl permet de modifier l'implementation sans avoir a recompiler...
Dans struct machin { int a; int b; }; la taille de struct machin est fixe. Il faudra tout recompiler si on veut rajouter des champs.
L'idee de pimpl, c'est de faire struct machin { struct pmachin *pimpl; };
et donc de mettre l'implementation entierement ailleurs. La taille de struct machin ne varie plus, c'est l'implementation qui varie (evidemment, a chaque creation d'un struct machin il faut un std::unique_ptr vers struct pmachin, comme dirait Sutter...)
In article <jg1g3k$7ft$1@news-rocq.inria.fr>,
Marc <marc.glisse@gmail.com> wrote:
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.
Pour ce que j'en sais, il faut finir par définir ces structures. C'est
ce que l'on veut éviter.
On la définit dans le fichier .c, qui n'est pas visible par l'utilisateur.
Enfin en tout cas j'ai l'impression que "pimpl" est la réponse à la
question d'origine.
*soupir*. Non, pimpl (dit aussi "compiler firewall") est la reponse a
une AUTRE question: pimpl permet de modifier l'implementation sans avoir
a recompiler...
Dans
struct machin {
int a;
int b;
};
la taille de struct machin est fixe. Il faudra tout recompiler si on veut
rajouter des champs.
L'idee de pimpl, c'est de faire
struct machin {
struct pmachin *pimpl;
};
et donc de mettre l'implementation entierement ailleurs. La taille de struct
machin ne varie plus, c'est l'implementation qui varie (evidemment, a chaque
creation d'un struct machin il faut un std::unique_ptr vers struct pmachin,
comme dirait Sutter...)
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.
Pour ce que j'en sais, il faut finir par définir ces structures. C'est ce que l'on veut éviter.
On la définit dans le fichier .c, qui n'est pas visible par l'utilisateur.
Enfin en tout cas j'ai l'impression que "pimpl" est la réponse à la question d'origine.
*soupir*. Non, pimpl (dit aussi "compiler firewall") est la reponse a une AUTRE question: pimpl permet de modifier l'implementation sans avoir a recompiler...
Dans struct machin { int a; int b; }; la taille de struct machin est fixe. Il faudra tout recompiler si on veut rajouter des champs.
L'idee de pimpl, c'est de faire struct machin { struct pmachin *pimpl; };
et donc de mettre l'implementation entierement ailleurs. La taille de struct machin ne varie plus, c'est l'implementation qui varie (evidemment, a chaque creation d'un struct machin il faut un std::unique_ptr vers struct pmachin, comme dirait Sutter...)
TSalm
C'est IMHO la solution parfaite. Il n'y a effectivement quasiment rien à changer. Merci à tous pour vos réponses.
A+ -TSalm
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;
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 ?
Oui, il n'y a que peu de choses à changer à ton code.
/* ----- implémentation ----- */ struct MonStruct { int data1; int data2; };
/* définitions de fonctions inchangées */ /* -------------------------- */
C'est ce qu'on appelle une structure opaque il me semble. J'imagine que c'est pour permettre ce genre de choses que le standard spécifie que « All pointers to structure types shall have the same representation and alignment requirements as each other. »
-- Utilisant le client e-mail révolutionnaire d'Opera : http://www.opera.com/mail/
C'est IMHO la solution parfaite.
Il n'y a effectivement quasiment rien à changer.
Merci à tous pour vos réponses.
A+
-TSalm
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;
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 ?
Oui, il n'y a que peu de choses à changer à ton code.
/* ----- implémentation ----- */
struct MonStruct {
int data1;
int data2;
};
/* définitions de fonctions inchangées */
/* -------------------------- */
C'est ce qu'on appelle une structure opaque il me semble. J'imagine que
c'est pour permettre ce genre de choses que le standard spécifie que
« All pointers to structure types shall have the same representation and
alignment requirements as each other. »
--
Utilisant le client e-mail révolutionnaire d'Opera :
http://www.opera.com/mail/
C'est IMHO la solution parfaite. Il n'y a effectivement quasiment rien à changer. Merci à tous pour vos réponses.
A+ -TSalm
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;
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 ?
Oui, il n'y a que peu de choses à changer à ton code.
/* ----- implémentation ----- */ struct MonStruct { int data1; int data2; };
/* définitions de fonctions inchangées */ /* -------------------------- */
C'est ce qu'on appelle une structure opaque il me semble. J'imagine que c'est pour permettre ce genre de choses que le standard spécifie que « All pointers to structure types shall have the same representation and alignment requirements as each other. »
-- Utilisant le client e-mail révolutionnaire d'Opera : http://www.opera.com/mail/
espie
In article , TSalm wrote:
Autre question, pourquoi utiliser "extern" pour les prototypes de fonctions ? Est-ce une recommandation pour garder une compatibilité avec certains compilateurs ?
Oui, en quelque sorte.
Il y a plusieurs modeles pour la compilation separee. Le fait de mettre "extern" devant tes prototypes de fonction globales te garantit que ca va marcher. Si tu l'oublies, ca risque de dependre du systeme (en general plus de l'editeur de liens que du compilateur), et si ca foire, ca va donner des erreurs tres tres bizarres.
(et il me semble qu'il y a des cas ou ca peut te mettre des jolis messages d'erreur si tu fais des conneries, meme si je n'en vois pas la comme ca...)
-> je ne vois aucune raison valable de ne pas mettre "extern" dans ces circonstances, c'est le dialecte portable clair qui fonctionne partout, et si tu l'oublies, ca peut merder quelque part...
In article <op.v8s4ddcik9rspk@papillon>, TSalm <tsalm@free.fr> wrote:
Autre question, pourquoi utiliser "extern" pour les prototypes de
fonctions ? Est-ce une recommandation pour garder une compatibilité avec
certains compilateurs ?
Oui, en quelque sorte.
Il y a plusieurs modeles pour la compilation separee. Le fait de mettre
"extern" devant tes prototypes de fonction globales te garantit que ca
va marcher. Si tu l'oublies, ca risque de dependre du systeme (en general
plus de l'editeur de liens que du compilateur), et si ca foire, ca va
donner des erreurs tres tres bizarres.
(et il me semble qu'il y a des cas ou ca peut te mettre des jolis messages
d'erreur si tu fais des conneries, meme si je n'en vois pas la comme ca...)
-> je ne vois aucune raison valable de ne pas mettre "extern" dans ces
circonstances, c'est le dialecte portable clair qui fonctionne partout,
et si tu l'oublies, ca peut merder quelque part...
Autre question, pourquoi utiliser "extern" pour les prototypes de fonctions ? Est-ce une recommandation pour garder une compatibilité avec certains compilateurs ?
Oui, en quelque sorte.
Il y a plusieurs modeles pour la compilation separee. Le fait de mettre "extern" devant tes prototypes de fonction globales te garantit que ca va marcher. Si tu l'oublies, ca risque de dependre du systeme (en general plus de l'editeur de liens que du compilateur), et si ca foire, ca va donner des erreurs tres tres bizarres.
(et il me semble qu'il y a des cas ou ca peut te mettre des jolis messages d'erreur si tu fais des conneries, meme si je n'en vois pas la comme ca...)
-> je ne vois aucune raison valable de ne pas mettre "extern" dans ces circonstances, c'est le dialecte portable clair qui fonctionne partout, et si tu l'oublies, ca peut merder quelque part...
Lucas Levrel
Le 28 janvier 2012, Marc Espie a écrit :
Il est tout a fait possible de manipuler des struct machin * sans connaitre struct machin, et ca evite de faire des casts tout moches.
Tu peux parfaitement faire
struct machin;
struct machin * new_machin(...);
dans ton .h
et n'avoir la definition effective de struct machin que dans le .c...
Tu as seulement besoin d'avoir la definition d'une structure pour avoir sa taille, et acceder a ses champs. Pour le reste, genre pour travailler avec des pointeurs, pas besoin de la definition.
Comment le compilo fait-il marcher l'arithmétique sur les pointeurs ? Est-ce qu'il met dans l'objet assemblé une sorte de sizeof(machin), à charge pour le linker de le remplacer par la bonne valeur ?
(J'espère que ma question est claire. Je n'ai qu'une vague idée des étapes qui conduisent de sources à un exécutable.)
-- LL
Le 28 janvier 2012, Marc Espie a écrit :
Il est tout a fait possible de manipuler des struct machin * sans connaitre
struct machin, et ca evite de faire des casts tout moches.
Tu peux parfaitement faire
struct machin;
struct machin *
new_machin(...);
dans ton .h
et n'avoir la definition effective de struct machin que dans le .c...
Tu as seulement besoin d'avoir la definition d'une structure pour avoir
sa taille, et acceder a ses champs. Pour le reste, genre pour travailler
avec des pointeurs, pas besoin de la definition.
Comment le compilo fait-il marcher l'arithmétique sur les pointeurs ?
Est-ce qu'il met dans l'objet assemblé une sorte de sizeof(machin), à
charge pour le linker de le remplacer par la bonne valeur ?
(J'espère que ma question est claire. Je n'ai qu'une vague idée des étapes
qui conduisent de sources à un exécutable.)
Il est tout a fait possible de manipuler des struct machin * sans connaitre struct machin, et ca evite de faire des casts tout moches.
Tu peux parfaitement faire
struct machin;
struct machin * new_machin(...);
dans ton .h
et n'avoir la definition effective de struct machin que dans le .c...
Tu as seulement besoin d'avoir la definition d'une structure pour avoir sa taille, et acceder a ses champs. Pour le reste, genre pour travailler avec des pointeurs, pas besoin de la definition.
Comment le compilo fait-il marcher l'arithmétique sur les pointeurs ? Est-ce qu'il met dans l'objet assemblé une sorte de sizeof(machin), à charge pour le linker de le remplacer par la bonne valeur ?
(J'espère que ma question est claire. Je n'ai qu'une vague idée des étapes qui conduisent de sources à un exécutable.)
-- LL
Marc
Lucas Levrel wrote:
Tu as seulement besoin d'avoir la definition d'une structure pour avoir sa taille, et acceder a ses champs. Pour le reste, genre pour travailler avec des pointeurs, pas besoin de la definition.
Comment le compilo fait-il marcher l'arithmétique sur les pointeurs ?
Il refuse s'il n'a pas la définition de l'objet pointé.
Lucas Levrel wrote:
Tu as seulement besoin d'avoir la definition d'une structure pour avoir
sa taille, et acceder a ses champs. Pour le reste, genre pour travailler
avec des pointeurs, pas besoin de la definition.
Comment le compilo fait-il marcher l'arithmétique sur les pointeurs ?
Il refuse s'il n'a pas la définition de l'objet pointé.
Tu as seulement besoin d'avoir la definition d'une structure pour avoir sa taille, et acceder a ses champs. Pour le reste, genre pour travailler avec des pointeurs, pas besoin de la definition.
Comment le compilo fait-il marcher l'arithmétique sur les pointeurs ?
Il refuse s'il n'a pas la définition de l'objet pointé.
espie
In article , Lucas Levrel wrote:
Le 28 janvier 2012, Marc Espie a écrit :
Il est tout a fait possible de manipuler des struct machin * sans connaitre struct machin, et ca evite de faire des casts tout moches.
Tu peux parfaitement faire
struct machin;
struct machin * new_machin(...);
dans ton .h
et n'avoir la definition effective de struct machin que dans le .c...
Tu as seulement besoin d'avoir la definition d'une structure pour avoir sa taille, et acceder a ses champs. Pour le reste, genre pour travailler avec des pointeurs, pas besoin de la definition.
Comment le compilo fait-il marcher l'arithmétique sur les pointeurs ? Est-ce qu'il met dans l'objet assemblé une sorte de sizeof(machin), à charge pour le linker de le remplacer par la bonne valeur ?
Il ne fait pas. Justement, si tu as juste la declaration de la structure, tu n'as pas la taille de la structure...
Rappel: tous les pointeurs ont la meme taille et la meme "nature" (hors les pointeurs de fonction, hors les extensions non standard a la far/near de l'epoque de msdos). Donc rien ne necessite d'avoir la definition de struct machin pour pouvoir faire, par exemple:
struct machin *tableau[TAILLE];
Evidemment, si tu as struct machin *p;
si tu veux faire p++;, ben la t'as besoin de la taille, et c'est normalement cable "en dur", meme si on pourrait imaginer un mecanisme dans le genre que tu suggeres (ca serait meme pas si eloigne de ce que font les editeurs de lien aujourd'hui, grace aux multiples modes d'adressage de la plupart des archis modernes, c'etait une des grosses raisons du passage de a.out/coff vers elf).
In article <alpine.LNX.2.00.1201291442590.6087@coulomb.u-pec.fr>,
Lucas Levrel <lucas.levrel@u-pec.fr> wrote:
Le 28 janvier 2012, Marc Espie a écrit :
Il est tout a fait possible de manipuler des struct machin * sans connaitre
struct machin, et ca evite de faire des casts tout moches.
Tu peux parfaitement faire
struct machin;
struct machin *
new_machin(...);
dans ton .h
et n'avoir la definition effective de struct machin que dans le .c...
Tu as seulement besoin d'avoir la definition d'une structure pour avoir
sa taille, et acceder a ses champs. Pour le reste, genre pour travailler
avec des pointeurs, pas besoin de la definition.
Comment le compilo fait-il marcher l'arithmétique sur les pointeurs ?
Est-ce qu'il met dans l'objet assemblé une sorte de sizeof(machin), à
charge pour le linker de le remplacer par la bonne valeur ?
Il ne fait pas. Justement, si tu as juste la declaration de la structure,
tu n'as pas la taille de la structure...
Rappel: tous les pointeurs ont la meme taille et la meme "nature" (hors les
pointeurs de fonction, hors les extensions non standard a la far/near de
l'epoque de msdos). Donc rien ne necessite d'avoir la definition de
struct machin pour pouvoir faire, par exemple:
struct machin *tableau[TAILLE];
Evidemment, si tu as
struct machin *p;
si tu veux faire p++;, ben la t'as besoin de la taille, et c'est normalement
cable "en dur", meme si on pourrait imaginer un mecanisme dans le genre que
tu suggeres (ca serait meme pas si eloigne de ce que font les editeurs de
lien aujourd'hui, grace aux multiples modes d'adressage de la plupart des
archis modernes, c'etait une des grosses raisons du passage de a.out/coff
vers elf).
Il est tout a fait possible de manipuler des struct machin * sans connaitre struct machin, et ca evite de faire des casts tout moches.
Tu peux parfaitement faire
struct machin;
struct machin * new_machin(...);
dans ton .h
et n'avoir la definition effective de struct machin que dans le .c...
Tu as seulement besoin d'avoir la definition d'une structure pour avoir sa taille, et acceder a ses champs. Pour le reste, genre pour travailler avec des pointeurs, pas besoin de la definition.
Comment le compilo fait-il marcher l'arithmétique sur les pointeurs ? Est-ce qu'il met dans l'objet assemblé une sorte de sizeof(machin), à charge pour le linker de le remplacer par la bonne valeur ?
Il ne fait pas. Justement, si tu as juste la declaration de la structure, tu n'as pas la taille de la structure...
Rappel: tous les pointeurs ont la meme taille et la meme "nature" (hors les pointeurs de fonction, hors les extensions non standard a la far/near de l'epoque de msdos). Donc rien ne necessite d'avoir la definition de struct machin pour pouvoir faire, par exemple:
struct machin *tableau[TAILLE];
Evidemment, si tu as struct machin *p;
si tu veux faire p++;, ben la t'as besoin de la taille, et c'est normalement cable "en dur", meme si on pourrait imaginer un mecanisme dans le genre que tu suggeres (ca serait meme pas si eloigne de ce que font les editeurs de lien aujourd'hui, grace aux multiples modes d'adressage de la plupart des archis modernes, c'etait une des grosses raisons du passage de a.out/coff vers elf).
Antoine Leca
Manuel Pégourié-Gonnard écrit :
C'est ce qu'on appelle une structure opaque il me semble.
Ou un type abstrait ?
<HS>
J'imagine que c'est pour permettre ce genre de choses que le standard spécifie que « All pointers to structure types shall have the same representation and alignment requirements as each other. »
Je croyais que l'objectif était plutôt de permettre le polymorphisme (voir la réponse de Samuel pour une extrapolation de l'idée).
En l'occurrence, du point de vue du standard, le "struct MonStruct" du typedef est un type incomplet, et la déclaration dans «implémentation» complète le _même_ type ; et évidemment, comme il s'agit du même type, il est compatible avec lui-même et tous les types pointeur qui en sont dérivés possèdent les mêmes représentations et contraintes d'alignement. </HS>
Antoine
Manuel Pégourié-Gonnard écrit :
C'est ce qu'on appelle une structure opaque il me semble.
Ou un type abstrait ?
<HS>
J'imagine que c'est pour permettre ce genre de choses que le standard
spécifie que « All pointers to structure types shall have the same
representation and alignment requirements as each other. »
Je croyais que l'objectif était plutôt de permettre le polymorphisme
(voir la réponse de Samuel pour une extrapolation de l'idée).
En l'occurrence, du point de vue du standard, le "struct MonStruct" du
typedef est un type incomplet, et la déclaration dans «implémentation»
complète le _même_ type ; et évidemment, comme il s'agit du même type,
il est compatible avec lui-même et tous les types pointeur qui en sont
dérivés possèdent les mêmes représentations et contraintes d'alignement.
</HS>
C'est ce qu'on appelle une structure opaque il me semble.
Ou un type abstrait ?
<HS>
J'imagine que c'est pour permettre ce genre de choses que le standard spécifie que « All pointers to structure types shall have the same representation and alignment requirements as each other. »
Je croyais que l'objectif était plutôt de permettre le polymorphisme (voir la réponse de Samuel pour une extrapolation de l'idée).
En l'occurrence, du point de vue du standard, le "struct MonStruct" du typedef est un type incomplet, et la déclaration dans «implémentation» complète le _même_ type ; et évidemment, comme il s'agit du même type, il est compatible avec lui-même et tous les types pointeur qui en sont dérivés possèdent les mêmes représentations et contraintes d'alignement. </HS>
Antoine
espie
In article <jg8fem$61g$, Antoine Leca wrote:
Je croyais que l'objectif était plutôt de permettre le polymorphisme (voir la réponse de Samuel pour une extrapolation de l'idée).
En l'occurrence, du point de vue du standard, le "struct MonStruct" du typedef est un type incomplet, et la déclaration dans «implémentation» complète le _même_ type ; et évidemment, comme il s'agit du même type, il est compatible avec lui-même et tous les types pointeur qui en sont dérivés possèdent les mêmes représentations et contraintes d'alignement. </HS>
Apres, si on veut etre plus precis, la compatibilite se situe au niveau des valeurs scalaires... la norme precise bien que deux structures contenant les memes champs dans le meme ordre vont etre compatibles (y compris pour un segment initial, donc pour le polymorphisme), ce qui est heureux...
ca a du etre precise lorsque les compilo C se sont mis a courir apres Fortran et utiliser les informations de type pour determiner si deux pointeurs peuvent pointer vers la meme zone memoire ou pas... en l'absence de restrict...
... ca a d'ailleurs foutu un gros bordel pour tous les gens qui utilisaient C comme un assembleur portable, et il a fallu attendre quelques versions majeures de gcc avant que ce dernier puisse sortir des warnings decents concernant ce type de souci ;(
In article <jg8fem$61g$1@shakotay.alphanet.ch>,
Antoine Leca <root@localhost.invalid> wrote:
Je croyais que l'objectif était plutôt de permettre le polymorphisme
(voir la réponse de Samuel pour une extrapolation de l'idée).
En l'occurrence, du point de vue du standard, le "struct MonStruct" du
typedef est un type incomplet, et la déclaration dans «implémentation»
complète le _même_ type ; et évidemment, comme il s'agit du même type,
il est compatible avec lui-même et tous les types pointeur qui en sont
dérivés possèdent les mêmes représentations et contraintes d'alignement.
</HS>
Apres, si on veut etre plus precis, la compatibilite se situe au niveau
des valeurs scalaires... la norme precise bien que deux structures contenant
les memes champs dans le meme ordre vont etre compatibles (y compris pour
un segment initial, donc pour le polymorphisme), ce qui est heureux...
ca a du etre precise lorsque les compilo C se sont mis a courir apres
Fortran et utiliser les informations de type pour determiner si deux
pointeurs peuvent pointer vers la meme zone memoire ou pas... en l'absence
de restrict...
... ca a d'ailleurs foutu un gros bordel pour tous les gens qui utilisaient
C comme un assembleur portable, et il a fallu attendre quelques versions
majeures de gcc avant que ce dernier puisse sortir des warnings decents
concernant ce type de souci ;(
Je croyais que l'objectif était plutôt de permettre le polymorphisme (voir la réponse de Samuel pour une extrapolation de l'idée).
En l'occurrence, du point de vue du standard, le "struct MonStruct" du typedef est un type incomplet, et la déclaration dans «implémentation» complète le _même_ type ; et évidemment, comme il s'agit du même type, il est compatible avec lui-même et tous les types pointeur qui en sont dérivés possèdent les mêmes représentations et contraintes d'alignement. </HS>
Apres, si on veut etre plus precis, la compatibilite se situe au niveau des valeurs scalaires... la norme precise bien que deux structures contenant les memes champs dans le meme ordre vont etre compatibles (y compris pour un segment initial, donc pour le polymorphisme), ce qui est heureux...
ca a du etre precise lorsque les compilo C se sont mis a courir apres Fortran et utiliser les informations de type pour determiner si deux pointeurs peuvent pointer vers la meme zone memoire ou pas... en l'absence de restrict...
... ca a d'ailleurs foutu un gros bordel pour tous les gens qui utilisaient C comme un assembleur portable, et il a fallu attendre quelques versions majeures de gcc avant que ce dernier puisse sortir des warnings decents concernant ce type de souci ;(