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 :

Retourner une structure


Sujet :

C

  1. #1
    Membre averti
    Inscrit en
    Octobre 2003
    Messages
    20
    Détails du profil
    Informations forums :
    Inscription : Octobre 2003
    Messages : 20
    Par défaut Retourner une structure
    Bonjour,

    Pour des soucis pratique j'ai écris des fonctions retournant une structure comme celle-ci:

    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
    typedef struct {
      int code;
      char label[RET_LABEL_SIZE+1];
    } RET_Value;
     
    RET_Value IN_WaitForFile(xxx) {
      RET_Value ret;
      .....
      ret.code = -1;
      strcpy(ret.label, "Cause de l'erreur");
      return ret;
    }
     
    main() {
      RET_Value ret;
      ...
      ret = RET_Value IN_WaitForFile(xxx);
      if(ret.code == -1) {
        printf("Erreur: %s\n", ret.label);
      }
    }
    Cela me permet de transporter le code d'erreur et son libellé d'appellant en appellant (genre Exception en Java).

    On (un collègue) m'a dis que c'était une grave erreur car l'espace mémoire pour la valeur retournée n'est alloué que dans la fonction IN_WaitForFile et peut être écrasé avant son utilisation dans le main.

    Est-ce vrai ?

    PS: je sais que c'est pas super propre, ni super efficace

  2. #2
    Membre éclairé
    Profil pro
    Inscrit en
    Avril 2006
    Messages
    349
    Détails du profil
    Informations personnelles :
    Âge : 39
    Localisation : France, Ille et Vilaine (Bretagne)

    Informations forums :
    Inscription : Avril 2006
    Messages : 349
    Par défaut
    Salut !

    Je ne suis pas sûr mais apparemment ta structure est déclarée globalement donc la mémoire doit être alloué également pour le main.

    Me trompes-je ?

    ++

  3. #3
    Membre éclairé
    Profil pro
    Inscrit en
    Avril 2006
    Messages
    349
    Détails du profil
    Informations personnelles :
    Âge : 39
    Localisation : France, Ille et Vilaine (Bretagne)

    Informations forums :
    Inscription : Avril 2006
    Messages : 349
    Par défaut
    Au fait tu as testé ton code ? Si la mémoire n'est pas allouée dans me main, tu t'en rendras compte assez vite : ya de grandes chances que ça plante si c'est le cas...

    ++

  4. #4
    Membre chevronné
    Avatar de Foobar1329
    Profil pro
    Inscrit en
    Juin 2006
    Messages
    283
    Détails du profil
    Informations personnelles :
    Âge : 44
    Localisation : France, Finistère (Bretagne)

    Informations forums :
    Inscription : Juin 2006
    Messages : 283
    Par défaut
    Citation Envoyé par MogDeChNord
    Bonjour,

    Pour des soucis pratique j'ai écris des fonctions retournant une structure comme celle-ci:

    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
    typedef struct {
      int code;
      char label[RET_LABEL_SIZE+1];
    } RET_Value;
     
    RET_Value IN_WaitForFile(xxx) {
      RET_Value ret;
      .....
      ret.code = -1;
      strcpy(ret.label, "Cause de l'erreur");
      return ret;
    }
     
    main() {
      RET_Value ret;
      ...
      ret = RET_Value IN_WaitForFile(xxx);
      if(ret.code == -1) {
        printf("Erreur: %s\n", ret.label);
      }
    }
    Cela me permet de transporter le code d'erreur et son libellé d'appellant en appellant (genre Exception en Java).

    On (un collègue) m'a dis que c'était une grave erreur car l'espace mémoire pour la valeur retournée n'est alloué que dans la fonction IN_WaitForFile et peut être écrasé avant son utilisation dans le main.

    Est-ce vrai ?

    PS: je sais que c'est pas super propre, ni super efficace
    Non, ton collègue a tort. La structure est renvoyee par valeur -> copie, comme tout en C d'ailleurs. Ce qui est dangereux, c'est de renvoyer un pointeur qui représente l'adresse d'une variable automatique située dans la fonction.

    Exple:

    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
    /* ça caca */
    char * branque(void)
    {
       char c; /* c est une varaible auto définie dans branque seulement*/
     
       /* on fait une copie de l'adresse de c que l'on retourne */
       /* oui, mais il est ou c une fois qu'on sort de branque ? */
       /* Eh ben il a disparu !! D'où boum si on essaie ensuite d'accéder
        * à cette valeur après appel à branque().
        */
       return  &c; 
       }
     
    /* ça OK, comme dans ton exemple */
    char getCR(void)
    {
       char c = 13; /**/
       /* On fait une copie de c que l'on retourne*/
       return  c; 
    }
    A+

  5. #5
    Membre Expert
    Inscrit en
    Décembre 2004
    Messages
    1 478
    Détails du profil
    Informations forums :
    Inscription : Décembre 2004
    Messages : 1 478
    Par défaut
    Citation Envoyé par MogDeChNord
    On (un collègue) m'a dis que c'était une grave erreur car l'espace mémoire pour la valeur retournée n'est alloué que dans la fonction IN_WaitForFile et peut être écrasé avant son utilisation dans le main.
    Ben non, c'est une valeur de retour. Tu as simplement defini un nouveau type et la valeur de retour sera copiee dans la variable qui recoit cette valeur dans la fonction appelante (ici, main). C'est strictement la meme chose que faire
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
     
      int f(void)
      {
         int i = 2;
         return i;
      }
     
      int main(void)
      {
         int val = f();
      }
    Et la, ca ne choque personne, n'est-ce pas?

    PS: je sais que c'est pas super propre, ni super efficace
    On evite en effet de retourner des structures, car le cout de la copie peut devenir prohibitif si la structure est grande. En general, on retourne un pointeur vers une structure allouee par la fonction.

  6. #6
    Membre chevronné
    Avatar de Foobar1329
    Profil pro
    Inscrit en
    Juin 2006
    Messages
    283
    Détails du profil
    Informations personnelles :
    Âge : 44
    Localisation : France, Finistère (Bretagne)

    Informations forums :
    Inscription : Juin 2006
    Messages : 283
    Par défaut
    Hello,

    Citation Envoyé par SesechXP
    Salut !

    Je ne suis pas sûr mais apparemment ta structure est déclarée globalement donc la mémoire doit être alloué également pour le main.

    Me trompes-je ?

    ++


    C'est quoi cette histoire d'allocation ? Il n'a que des variables automatiques dans son code, pas d'allocation dynamique.

    La structure n'est pas déclarée globalement, elle est locale à main().

    C'est le type (RET_Value) qui est défini globalement.

    A+

  7. #7
    Expert éminent
    Avatar de Emmanuel Delahaye
    Profil pro
    Retraité
    Inscrit en
    Décembre 2003
    Messages
    14 512
    Détails du profil
    Informations personnelles :
    Âge : 68
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Retraité

    Informations forums :
    Inscription : Décembre 2003
    Messages : 14 512
    Par défaut
    Citation Envoyé par MogDeChNord
    Cela me permet de transporter le code d'erreur et son libellé d'appellant en appellant (genre Exception en Java).

    On (un collègue) m'a dis que c'était une grave erreur car l'espace mémoire pour la valeur retournée n'est alloué que dans la fonction IN_WaitForFile et peut être écrasé avant son utilisation dans le main.

    Est-ce vrai ?

    PS: je sais que c'est pas super propre, ni super efficace
    C'est faux. Il y a recopie de la structure. Par contre, il est vrai que ce n'est pas efficace.

    La Bonne Pratique consiste à retourner un code d'erreur unique (enum) et à utiliser au dernier moment la transformation en chaine à l'aide d'une fonction spécialisée.

  8. #8
    Expert éminent
    Avatar de Emmanuel Delahaye
    Profil pro
    Retraité
    Inscrit en
    Décembre 2003
    Messages
    14 512
    Détails du profil
    Informations personnelles :
    Âge : 68
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Retraité

    Informations forums :
    Inscription : Décembre 2003
    Messages : 14 512
    Par défaut
    Citation Envoyé par SesechXP
    Je ne suis pas sûr mais apparemment ta structure est déclarée globalement donc la mémoire doit être alloué également pour le main.

    Me trompes-je ?
    Mais keskidi...

  9. #9
    Expert éminent
    Avatar de Emmanuel Delahaye
    Profil pro
    Retraité
    Inscrit en
    Décembre 2003
    Messages
    14 512
    Détails du profil
    Informations personnelles :
    Âge : 68
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Retraité

    Informations forums :
    Inscription : Décembre 2003
    Messages : 14 512
    Par défaut
    Citation Envoyé par SesechXP
    Au fait tu as testé ton code ? Si la mémoire n'est pas allouée dans me main, tu t'en rendras compte assez vite : ya de grandes chances que ça plante si c'est le cas...
    Tu arrêtes de raconter n'importe quoi... ça me saoûle...

  10. #10
    Membre Expert
    Avatar de Pragmateek
    Homme Profil pro
    Formateur expert .Net/C#
    Inscrit en
    Mars 2006
    Messages
    2 635
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 38
    Localisation : France, Val de Marne (Île de France)

    Informations professionnelles :
    Activité : Formateur expert .Net/C#
    Secteur : Conseil

    Informations forums :
    Inscription : Mars 2006
    Messages : 2 635
    Par défaut
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    main() {
      RET_Value ret;
      ...
      ret = RET_Value IN_WaitForFile(xxx);
      if(ret.code == -1) {
        printf("Erreur: %s\n", ret.label);
      }
    }
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    int main (void){
    ...
    return EXIT_SUCCESS;
    }

  11. #11
    Membre averti
    Inscrit en
    Octobre 2003
    Messages
    20
    Détails du profil
    Informations forums :
    Inscription : Octobre 2003
    Messages : 20
    Par défaut
    Merci pour vos réponses:

    SesechXP > J'ai pas eu de pb depuis plusieurs mois en utilisant ce procédé plusieurs fois par secondes. Mais nous cherchons la cause d'un plantage dans une de ces fonctions et ce code a interpellé mon collègue.

    Foobar1329, DaZumba, Emmanuel Delahaye > C'est bien ce que je pensais.

    seriousme > Je ne comprend pas ton intervention

  12. #12
    Membre Expert
    Avatar de Pragmateek
    Homme Profil pro
    Formateur expert .Net/C#
    Inscrit en
    Mars 2006
    Messages
    2 635
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 38
    Localisation : France, Val de Marne (Île de France)

    Informations professionnelles :
    Activité : Formateur expert .Net/C#
    Secteur : Conseil

    Informations forums :
    Inscription : Mars 2006
    Messages : 2 635
    Par défaut
    seriousme > Je ne comprend pas ton intervention
    C'est juste une remarque sur le prototype du "main":
    The function called at program startup is named main. The implementation declares no
    prototype for this function. It shall be defined with a return type of int and with no
    parameters:
    int main(void) { /* ... */ }
    or with two parameters (referred to here as argc and argv, though any names may be
    used, as they are local to the function in which they are declared):
    int main(int argc, char *argv[]) { /* ... */ }
    or equivalent;9) or in some other implementation-defined manner.
    dixit la norme.

  13. #13
    Membre averti
    Inscrit en
    Octobre 2003
    Messages
    20
    Détails du profil
    Informations forums :
    Inscription : Octobre 2003
    Messages : 20
    Par défaut
    Citation Envoyé par seriousme
    C'est juste une remarque sur le prototype du "main":

    dixit la norme.
    Ah OK, mais le code de mon topic n'est le reflet exacte de la réalité, c'était juste pour illustrer ma question.

    Merci quand même pour la précision

  14. #14
    Membre chevronné
    Avatar de Foobar1329
    Profil pro
    Inscrit en
    Juin 2006
    Messages
    283
    Détails du profil
    Informations personnelles :
    Âge : 44
    Localisation : France, Finistère (Bretagne)

    Informations forums :
    Inscription : Juin 2006
    Messages : 283
    Par défaut
    Hello,

    Citation Envoyé par MogDeChNord
    J'ai pas eu de pb depuis plusieurs mois en utilisant ce procédé plusieurs fois par secondes. Mais nous cherchons la cause d'un plantage dans une de ces fonctions et ce code a interpellé mon collègue.
    Peut être un libelle qui ne rentre pas dans le membre label de ta structure si tu ne verifies pas la longeueur des chaines de caractères source avant de faire un strcpy() ?

    A+

  15. #15
    Membre averti
    Inscrit en
    Octobre 2003
    Messages
    20
    Détails du profil
    Informations forums :
    Inscription : Octobre 2003
    Messages : 20
    Par défaut
    Nous avons écarté cette hypothèse très facilement vérifiable, y'a plein d'autre endroit où une coquille a pû se glisser.

    Ce sera peut-être l'objet d'un autre topic

Discussions similaires

  1. [WD14] Fenêtre qui retourne une structure
    Par bombseb dans le forum WinDev
    Réponses: 12
    Dernier message: 24/12/2009, 12h25
  2. Retourner une structure ou -1 si erreur
    Par micaz dans le forum C
    Réponses: 7
    Dernier message: 21/04/2009, 09h02
  3. [JAXB] Unmarshalling retourne une structure vide
    Par Mat1664 dans le forum Persistance des données
    Réponses: 2
    Dernier message: 07/03/2008, 11h43
  4. retourner une structure pour une fonction
    Par emardjean dans le forum C
    Réponses: 5
    Dernier message: 24/01/2007, 20h36
  5. Réponses: 6
    Dernier message: 14/02/2006, 11h29

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