Bonjour,

Voilà : je ne pige pas du tout comment ça fonctionne, ou pas. Ca ressemble un peu à la discussion à propos de l'exportation de chaînes constantes, mais là le cas est plus clair.

(Je me demandais au départ si c'était vivable en pratique, comme on m'a recommandé, de ne pas définir "par référence" un type viariable ; donc un type dont les instances seront passées explicitement par références à nombre des routines qui s'occuppent de lui. Ce qui veut dire qu'on a des '*' et des '&' à gauche et à droite, et qu'il faut bien faire gaffe quand une variable dénote directement, ou au contraire un pointeur sur, une entité de ce type. Je voulais faire un essai exemplaire, qui commence avec la déf de routines pour créer des instances de ce type. Et ça commence ainsi : )
Voilà trois petites routines pour créer des spécimens de type S et un test qui affiche leur contenu:

Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
typedef struct { uint i ; } S ;
 
S s_make (uint i ) {
   return (S) {i} ;
}
 
S * s_new1 (uint i ) {
   S s = {i} ;
   return & s ;
}
 
S * s_new2 (uint i ) {
   return & ((S) {i}) ;
}
 
void test_make () {
   puts ("=== test ========================================================") ;
 
   S s = s_make (0) ;
   printf ("s : (i:%u)\n", s.i) ;
 
   S * ps1 = s_new1 (1) ;
   printf ("ps1 --> (i:%u)\n", ps1->i) ;
 
   S * ps2 = s_new2 (2) ;
   printf ("ps2 --> (i:%u)\n", ps2->i) ;
 
   end_test () ;
}
(Il y a aussi main() qui appelle test() qui appelle test_make().)

Résultat: C a l'air d'accord ! Voilà :

Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
=== test ========================================================
s : (i:0)
ps1 --> (i:1)
ps2 --> (i:2)
=================================================================
Alors, questions:

1. gcc m'affiche un warning à propos de s_new1 parce que j'échappe une donnée locale:
Code : Sélectionner tout - Visualiser dans une fenêtre à part
   a.c:13:4: warning: function returns address of local variable [enabled by default]
et il a raison ! mais il ne dit rien à propos de s_new_2 qui fait la même chose. Comment interprétez vous cela ? [La commande de compilation inclut "-Wall -Wextra".]

2. Selon moi, ni s_new_1, ni s_new2, ne devraient marcher : elle retournent toutes les deux un pointeur sur une donnée locale. Ca ne veut rien dire, je devrais avoir un segfault ou qq chose comme ça. Et pourtant, ça marche !
Qu'est-ce que je ne pige pas ?

Valgrind (précisément l'outil 'memcheck') lui me dit bien que je transgresse une règle, là. Voilà son commentaire:

Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
 
=== test ========================================================
s : (i:1)
==9275== Invalid read of size 4
==9275==    at 0x804922E: test_make (a.c:33)
==9275==    by 0x804927C: test (a.c:44)
==9275==    by 0x8049295: main (a.c:49)
==9275==  Address 0xbe922254 is just below the stack ptr.  To suppress, use: --workaround-gcc296-bugs=yes
==9275== 
ps --> (i:1)
==9275== Invalid read of size 4
==9275==    at 0x8049253: test_make (a.c:36)
==9275==    by 0x804927C: test (a.c:44)
==9275==    by 0x8049295: main (a.c:49)
==9275==  Address 0xbe922254 is just below the stack ptr.  To suppress, use: --workaround-gcc296-bugs=yes
==9275== 
ps --> (i:2)
=================================================================
(a.c:33) et (a.c:36) sont les seconde et troisième lignes de printf. C'est exactement ça, en fait, je crois : je lis des données qui viennent de disparaître de la pile. Elles n'ont pas encore été écrasées, peut-être, mais elles sont en-dehors de la zone dans maquelle mon prog devrait être autorisé à lire, non ?
Je ne comprends plus grand chose...

Merci,
Denis