Re: [gull] Subtilité de C n° 4 : déclaration de struct

Marc Mongenet marc at mongenet.ch
Fri Apr 18 19:02:24 CEST 2008


Le 17/04/08, Leopoldo Ghielmetti<leopoldo.ghielmetti at a3.epfl.ch> a écrit :
>
>  Il giorno mer, 16/04/2008 alle 21.31 +0200, Marc Mongenet ha scritto:
>
> > Le 15/04/08, Leopoldo Ghielmetti<leopoldo.ghielmetti at a3.epfl.ch> a écrit :
>  >
>  > >  On Tue, 2008-04-15 at 02:37 +0200, Marc Mongenet wrote:
>  > >  >
>  > >  >
>  > >  > ----------------------- ex2.c
>  > >  > struct s { int i; } v;
>  > >  >
>  > >  > void f(void) {
>  > >  >       struct s;
>  > >  >       struct ps { struct s *p; } ps;
>  > >  >       struct s { int j; } v;
>  > >  >       ps.p = &v;
>  > >  >       ps.p->j = 0;
>  > >  > }
>  > >  > -----------------------
>  > >
>  Oui, en effet, je me suis mal expliqué. La structure s est de toute
>  façon redéclarée.
>  Les deux codes seraient par contre identiques si la structure ps était
>  déclarée juste après la structure s

Tout à fait.

>
>  Tu aurais aussi un joli effet si tu ajoutais la déclaration suivante
>  juste après la déclaration de ps et avant la declaration de la structure
>  s:
>  int ssize = sizeof(struct s);
>
>  Je n'ai pas vérifié en compilant la chose mais j'imagine que dans le
>  premier cas ça marche et ssize prend la valeur correspondante à la
>  taille de la structure s, dans le deuxième cas ça plante à la
>  compilation car la structure s n'a pas encore été déclarée.
>

Il y a une erreur de compilation car la structure s est incomplètement
déclarée, et qu'on n'a pas le droit d'utiliser sizeof sur un type
incomplètement déclaré, nuance. ;-)

>
> Dans le premier cas rien (car il confirme que la struct s existe bel et
>  bien), dans le deuxième il annonce la future déclaration de la structure
>  s. Ça ne me parait pas si tordu que ça.

Dans le 2e cas, le « struct s; » déclare un type incomplet.
C'est un concept un peu différent d'une déclaration avancée
à la Pascal, car on n'est pas obligé de compléter plus bas un
type incomplet, et on peut l'utiliser pour toute opération qui
n'a pas besoin de savoir ce qu'il y a dans la structure.

L'exemple typique d'usage des types incomplets et celui des
pointeurs opaques. Ça s'utilise en C, c'est un idiome courant
de C++ (sous le nom de Pimpl notamment), et je vois que ça
existe même en Ada : http://en.wikipedia.org/wiki/Opaque_pointer

Exemple en C adapté de l'exemple de Wikipédia :
--------------------------- opaque.h
typedef struct foo *foo_handle;

foo_handle create(int);
void destroy(foo_handle);
int do(foo_handle, int);
---------------------------

Sans savoir ce qui se trouve dans struct foo, on peut
pourtant créer, détruire et manipuler des objets de ce type
par l'intermédiaire de foo_handle.

Une dernière variation du quizz pour conclure :

----------------- ex3.c
struct s { char c; };

unsigned f(void) {
  struct s;
  {
    struct ps { struct s *p; } ps;
    struct s { char c1; char c2; };
    return sizeof *ps.p;
  }
}
-----------------

Que me dit `gcc -c ex3.c` ?
Que retourne f() ?

Marc Mongenet

PS : Tout ces subtilités sont également valables pour les unions.



More information about the gull mailing list