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:
(Il y a aussi main() qui appelle test() qui appelle test_make().)
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 () ; }
Résultat: C a l'air d'accord ! Voilà :
Alors, questions:
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) =================================================================
1. gcc m'affiche un warning à propos de s_new1 parce que j'échappe une donnée locale:
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".]
Code : Sélectionner tout - Visualiser dans une fenêtre à part a.c:13:4: warning: function returns address of local variable [enabled by default]
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:
(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 ?
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) =================================================================
Je ne comprends plus grand chose...
Merci,
Denis
Partager