IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

 C Discussion :

structs implantées par valeurs mais stockées par référence


Sujet :

C

  1. #1
    Membre habitué
    Profil pro
    amateur
    Inscrit en
    Avril 2012
    Messages
    145
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations professionnelles :
    Activité : amateur
    Secteur : Arts - Culture

    Informations forums :
    Inscription : Avril 2012
    Messages : 145
    Points : 144
    Points
    144
    Par défaut structs implantées par valeurs mais stockées par référence
    Bonjour,

    J'ai un problème avec les structs implantées par valeurs mais stockées par référence. Voilà ce que je veux dire:

    Imaginons une struct S qui fait disons qq mots de taille. Par nature, pour ainsi dire, elle peut être une pure donnée, autrement dit avoir une sémantique dite de valeur. Son implantation en fait donc un type de struct tout simple; les quelques routines spécifiques à ce type peuvent recevoir la struct (et non un pointeur). (En particulier, si elle est conceptuellement non mutable.) Le point clé est que la création d'une S est directe et que donc le code client reçoit bien une S et non pas une référence, un pointeur, et le manipule ainsi.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
       S s = s_make (...) ;
       // manier s tel que
     
       // et non pas
       S * s = s_new (...) ;
    Mais que se passe-t-il si cette struct est intégrée dans d'autres types de données, à un niveau supérieur? Dans ce cas, pour diverses raisons (poids d'un S en lui-même, uniformité de taille dans une union, ...) il peut être souhaitable de stocker une référence et non plus la struct elle-même.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
       S s = s_make (...) ;
       x.s = & s_data ;
    Alors c'est là que je suis un peu perdu, j'arrive pas à penser le problème. Le danger là est bien que s est une donnée locale et donc un pointeur sur elle cesse d'être valide dès qu'on sort du bloc. On devrait allouer s sur le tas. Correct?
    Mais quand est-ce que le code ci-dessus cesse d'être sûr, en fait? Normalement le problème avec un pointeur sur une donéée locale se pose lorsque ce pointeur est retourné par la fonction. Ici, il n'y a rien de tel: il est placé dans une structure. Alors, qu'est-ce qui se passe? [1]
    Et plus généralement, quand est-ce que je peux ou pas stocker par référence une structure non allouée sur le tas?

    Mon problème exact est celui-ci: j'ai un type Texte (dont j'ai parlé sur ce forum) qui est assez léger (2 mots) et immuable. Donc, tout l'implantation est par valeur, il n'y a pas une réf dans toute le module. Un avantage est que les structs elles-mêmes ne sont pas allouées (seul leur contenu l'est) et donc aussi n'ont pas à âtre libérées. Mais à un plus haut niveau le type Text fait partie d'une union dont tous les autres memebreas ont la taille d'un mot
    * soit parce que la donnée fait cette taille au maximum,
    * soit parce qu'elle sont des données complexes mais naturellement maniées par référence (entre autres parce qu'elle sont mutables, elles).
    Mon problème est que je voudrais stocker des textes là par référence pour ne pas doubler la taille de l'union, mais aussi éviter d'allouer les struct Text sur le tas.
    c'est possible?

    Merci,
    denis

    [1] PS: J'ai l'impression suivante (qui peut être fausse). Si la structure de donnée 'x' dans laquelle la réf à 's' est placée est elle-même locale, ne sort pas de la fonction directement ou indirectement, alors ça roule. Sinon, on devrait avoir un problème.
    Mais ça ne fait que déplacer le problème que j'arrive pas à penser. En fait, le coeur de mon interrogation semble être: dans quelles situations de programmation est-ce qu'on peut faire ça ou pas ? dans quelles situations est-ce qu'on doit allouer une struct-donnée sur le tas qui n'a pas besoin de l'etre à la base pour des raisons sémantiques ? Et surtout, à quoi correspondent conceptuellement les situations ou une struct-donnée peut ou non rester non allouée ? que signifient de telles situations et donc comment les reconnaître par le sens qu'elles ont ?

  2. #2
    Expert éminent sénior
    Avatar de diogene
    Homme Profil pro
    Enseignant Chercheur
    Inscrit en
    Juin 2005
    Messages
    5 761
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : Enseignant Chercheur
    Secteur : Enseignement

    Informations forums :
    Inscription : Juin 2005
    Messages : 5 761
    Points : 13 926
    Points
    13 926
    Par défaut
    Si je comprend (?) ce que tu veux dire dans ton deuxième code (s_data ??) si x est une structure X comportant un pointeur sur un S, et on a dans une fonction :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    X fonc(...)
    { ...
       S s = s_make (...) ;
       x.s = & s;
       return x;
    }
    Alors, le champ s de la structure X retournée est illégal et ne doit pas être utilisé.

    1] PS: J'ai l'impression suivante (qui peut être fausse). Si la structure de donnée 'x' dans laquelle la réf à 's' est placée est elle-même locale, ne sort pas de la fonction directement ou indirectement, alors ça roule. Sinon, on devrait avoir un problème.
    Oui
    Publication : Concepts en C

    Mon avatar : Glenn Gould

    --------------------------------------------------------------------------
    Une réponse vous a été utile ? Remerciez son auteur en cliquant le pouce vert !

  3. #3
    Membre habitué
    Profil pro
    amateur
    Inscrit en
    Avril 2012
    Messages
    145
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations professionnelles :
    Activité : amateur
    Secteur : Arts - Culture

    Informations forums :
    Inscription : Avril 2012
    Messages : 145
    Points : 144
    Points
    144
    Par défaut quelques essais
    J'ai fait quelques essais pour essayer de mieux comprendre. D'abord, je créais une struct de type S comme pure valeur (sans réf), et l'intégrais par référence dans une struct de type T, mais en utilisant celle-ci sur place. La fonction make_t ci-dessous créait intialement un t puis l'affichait directment.

    Ensuite j'ai modifié un peu mon code de test:
    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
    30
    31
    32
    33
    typedef struct {
       uint i ;
       uint j ;
    } S ;
    S make_s (uint i, uint j) {
       S s = {i,j} ;
       return s ;
    }
     
    typedef struct {
       S * s ;
       bool b ;
    }  T ;
    T make_t (S s) {
       T t = {&s, true} ;
       return t ;
    }
     
    void note_t1 (T t) {
       printf ("t : {&{%u,%u}, %u}\n", t.s->i, t.s->j, t.b) ;
    } ;
    void note_t2 (T t) {
       S s = *t.s ;
       printf ("t : {&{%u,%u}, %u}\n", s.i, s.j, t.b) ;
    } ;
     
    // test ************************
    void test (void) {
       S s = make_s(3,9) ;
       T t = make_t(s) ;
       note_t1 (t) ;
       note_t2 (t) ;
    }
    Là, il est clair que make_t fait ce qu'en anglais on appelle pointer escape, c'est-à-dire renvoyer (une donnée qui contient) un pointeur dont la cible est locale, sur la pile. (Ca ressemble un peu à mes précédentes interrogations sur les strings allouées ou non.) La fonction reçoit (une copie locale de) s, en met un pointeur dans t et retourne (une copie de) t, qui contient donc un pointeur invalide.
    Pourtant note_t1 écrit bien t sans problème. Pour rendre les choses encore plus claires, j'ai écrit une variante note_t2 qui déréférence explicitement le pointeur (dans note_t1 ça reste implicite).

    Alors voilà ce dont je voudrais être sûr:
    1. C'est du code erronné, qui ne marche que par hasard du fait que s n'a pas encore été écrasé en mémoire, ou ce genre de chose.
    2. Pour que ce soit correct et que ça fonctionne bien dans tous les cas, il n'y a pas d'autre moyen que d'allouer s (soit dès le départ, et changer make_t pour qu'il prenne S*, ou allouer s dans make_t).

    Mais là je n'ai aucune erreur et aucun warning par gcc. Néanmoins, Valgrind me dit pour chaque printf:
    Citation Envoyé par Valgrind
    Use of uninitialised value of size 4
    Conditional jump or move depends on uninitialised value(s)
    Bon, je sais plus trop quoi penser...

  4. #4
    Expert éminent sénior
    Avatar de diogene
    Homme Profil pro
    Enseignant Chercheur
    Inscrit en
    Juin 2005
    Messages
    5 761
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : Enseignant Chercheur
    Secteur : Enseignement

    Informations forums :
    Inscription : Juin 2005
    Messages : 5 761
    Points : 13 926
    Points
    13 926
    Par défaut
    1. C'est du code erronné, qui ne marche que par hasard du fait que s n'a pas encore été écrasé en mémoire, ou ce genre de chose.
    Oui, donc le comportement est imprévisible. Le code est buggé
    2. Pour que ce soit correct et que ça fonctionne bien dans tous les cas, il n'y a pas d'autre moyen que d'allouer s (soit dès le départ, et changer make_t pour qu'il prenne S*, ou allouer s dans make_t).
    ou d'allouer dynamiquement s dans make_t
    Publication : Concepts en C

    Mon avatar : Glenn Gould

    --------------------------------------------------------------------------
    Une réponse vous a été utile ? Remerciez son auteur en cliquant le pouce vert !

  5. #5
    Membre habitué
    Profil pro
    amateur
    Inscrit en
    Avril 2012
    Messages
    145
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations professionnelles :
    Activité : amateur
    Secteur : Arts - Culture

    Informations forums :
    Inscription : Avril 2012
    Messages : 145
    Points : 144
    Points
    144
    Par défaut
    Citation Envoyé par diogene Voir le message
    Oui, donc le comportement est imprévisible. Le code est buggé

    ou d'allouer dynamiquement s dans make_t
    Oui, merci Diogene pour ces réponses (et ta précision).

    J'en profite pour demander si "allocation dynamique"
    * est synonyme d'allocation sur le tas,
    * est synonyme d'allocation sur le tas en C,
    * ne désigne pas le même domaine de signification
    Si le dernier point est correct, l'un pourrait recouvrir l'autre mais englober d'autres cas, ou alors ils pourraient avoir une intersection commune mais chacun aussi désigner d'autres cas.

    denis

  6. #6
    Expert éminent sénior
    Avatar de Médinoc
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Septembre 2005
    Messages
    27 369
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 40
    Localisation : France

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Septembre 2005
    Messages : 27 369
    Points : 41 518
    Points
    41 518
    Par défaut
    Je dirais que c'est synonyme d'allocation sur le tas (ou dans certains systèmes, sur UN tas), en général.
    SVP, pas de questions techniques par MP. Surtout si je ne vous ai jamais parlé avant.

    "Aw, come on, who would be so stupid as to insert a cast to make an error go away without actually fixing the error?"
    Apparently everyone.
    -- Raymond Chen.
    Traduction obligatoire: "Oh, voyons, qui serait assez stupide pour mettre un cast pour faire disparaitre un message d'erreur sans vraiment corriger l'erreur?" - Apparemment, tout le monde. -- Raymond Chen.

  7. #7
    Membre habitué
    Profil pro
    amateur
    Inscrit en
    Avril 2012
    Messages
    145
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations professionnelles :
    Activité : amateur
    Secteur : Arts - Culture

    Informations forums :
    Inscription : Avril 2012
    Messages : 145
    Points : 144
    Points
    144
    Par défaut
    Citation Envoyé par Médinoc Voir le message
    Je dirais que c'est synonyme d'allocation sur le tas (ou dans certains systèmes, sur UN tas), en général.
    Merci!

    Denid

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. Réponses: 6
    Dernier message: 20/01/2013, 14h08
  2. [getElementById] Id reconnu par CSS mais pas par getElementById
    Par Hibou57 dans le forum Général JavaScript
    Réponses: 2
    Dernier message: 22/07/2007, 08h47
  3. Réponses: 22
    Dernier message: 18/05/2007, 17h46
  4. prompt interprété par firefox mais pas par IE
    Par calitom dans le forum Général JavaScript
    Réponses: 15
    Dernier message: 06/02/2007, 17h58
  5. Fonction Javascript acceptée par Firefox mais refusée par IE
    Par strat0 dans le forum Général JavaScript
    Réponses: 5
    Dernier message: 21/01/2007, 20h32

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo