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 :

De l'utilisation des char const *


Sujet :

C

  1. #1
    Modérateur

    Avatar de Bktero
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Juin 2009
    Messages
    4 492
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 37
    Localisation : France, Loire Atlantique (Pays de la Loire)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels

    Informations forums :
    Inscription : Juin 2009
    Messages : 4 492
    Billets dans le blog
    1
    Par défaut De l'utilisation des char const *
    Bonjour,

    Je suis en train de faire petit programme en C utilisant le libusb pour communiquer avec mon téléphone Android. J'ai voulu faire une fonction pour convertir un code d'erreur en chaîne de caractère, et n'ayant pas fait de C depuis longtemps (je suis plutôt dans Java et C++ ces derniers temps), j'ai fait des trucs pas beaux avec des chaînes de caractères.

    J'ai fait une fonction qui en gros ressemblait à ça :
    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
    char* libusbErrorTranslate(const int errorNumber)
    {
        char* errorMessage = (char*)malloc(100*sizeof(char));
        if(NULL==errorMessage)
        {
            puts("*** Impossible d'allouer l'espace memoire pour stocker le message d'erreur de la libusb !");
            perror("*** Errno ");
        }
     
        switch(errorNumber)
        {
            case 0 :
                errorMessage="LIBUSB_SUCCESS";
     
            // plusieurs autres cases...
     
            default :
                errorMessage="(NONE)";
        }
        return errorMessage;
    }
    Ça marchait très bien dans la fonction appelante (pour obtenir la chaîne et l'afficher). J'ai ensuite voulu rajouter un free puisque dans cette fonction appelante puisque j'avais fait un malloc. Ca c'est fini en bon gros crash (l'opérateur = avec les chaînes en C... ), la zone pointée n'étant plus celle allouée avec malloc ,et j'ai modifié comme suit pour que ça marche :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
                strncpy (errorMessage, "(NONE)", 100);
                *(errorMessage+99)='\n';
    J'ai du coup parcouru la FAQ de Developpez et je suis tombé sur cet entrée.

    Je me suis alors posé des questions bêtes :
    1. quel est l'intérêt de ce genre de variable ?
    2. quand est libérée la mémoire ?
    3. si je change la valeur (4e ligne dans l'exemple de la FAQ), que devient l'espace mémoire de la précédente chaîne ?
    4. peut-on retourner ce pointeur avec une fonction ?
    5. est ce que l'affectation peut planter en cours d'exécution (si pas de mémoire disponible) et comment cela se passe ?


    Mes réponses sont :
    1. ne pas avoir à se soucier de la taille à allouer
    2. (pas d'idée...)
    3. à la fin du bloc où la variable a été déclarée
    4. non si la variable est définie dans cette fonction
    5. (pas d'idée... plantage brutal ?)


    Bref, si certains connaissent bien le comportement de ces choses, je les remercie d'avance d'éclairer ma lanterne

  2. #2
    Membre émérite
    Avatar de Kirilenko
    Homme Profil pro
    Étudiant
    Inscrit en
    Décembre 2011
    Messages
    234
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 28
    Localisation : France, Gironde (Aquitaine)

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Décembre 2011
    Messages : 234
    Par défaut
    Il me semble que :

    définit un pointeur vers une chaîne de caractère statique.
    Par conséquent, la mémoire est libérée à la fin de l'exécution du programme. On peut donc retourner cette chaîne de caractère à partir d'une fonction donnée.
    Récursivité en C : épidémie ou hérésie ?

    "Pour être un saint dans l'Église de l'Emacs, il faut vivre une vie pure. Il faut se passer de tout logiciel propriétaire. Heureusement, être célibataire n'est pas obligé. C'est donc bien mieux que les autres églises" - Richard Stallman

  3. #3
    Membre Expert
    Homme Profil pro
    Inscrit en
    Décembre 2011
    Messages
    1 186
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations forums :
    Inscription : Décembre 2011
    Messages : 1 186
    Par défaut
    Bonjour,

    Ci-dessous quelques réponses aux questions :
    1.Quel est l'intérêt de ce genre de variable ?
    Effectivement, un intérêt est de ne pas avoir à se soucier de la taille mémoire à réserver.
    Mais également comme toute constante, de pouvoir la réutiliser à différent endroit du code (à partir du pointeur sur la chaîne, bien sûr, pas en retapant la chaîne ).

    2. quand est libérée la mémoire ?
    A cette question, il faudrait commencer par répondre à "Quand est alloué la mémoire ?"
    Sauf erreur de ma part, le compilateur parcours le code au moment de la compilation à recherche de constantes (notamment des constantes chaînes de caractère).
    Après optimisation, les constantes sont regroupées par le compilateur dans une section.
    Cette section sera chargées automatiquement en mémoire au lancement du programme (avant d'arriver au main()).
    Maintenant on comprend bien que ces constantes restent en mémoire tant que le programme s'exécute. (comme dit par Kirilenko)

    3. Si je change la valeur [du pointeur] (4e ligne dans l'exemple de la FAQ), que devient l'espace mémoire de la précédente chaîne ?
    Comme tout pointeur en C/C++ (pas de Garbage Collector) : ce n'est pas parce que plus aucun pointeur ne pointe sur un espace mémoire,
    que la mémoire est libérée.
    Donc dans le cas de l'exemple de la FAQ, le pointeur pointait sur une constante, et à la 4ème ligne pointe sur une autre constante.
    Et comme expliqué en (2) les constantes restent en mémoire jusqu'à la fin du programme.

    Par contre, si on (je ne citerais personne ) s'amuse à faire :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    char * p = malloc (100 * sizeof(char)); // alloue dynamiquement de la mémoire
    p = "bonjour";  // p pointe maintenant sur une constante, la mémoire allouée précédemment est perdue !!
    Et bien on a plus de pointeur sur la mémoire allouée en ligne 1. Du coup il n'y plus possible de libérer la mémoire.


    4. Peut-on retourner ce pointeur avec une fonction ?
    Comme expliqué plus haut, si le pointeur pointe sur une chaîne constante, la chaîne restera en mémoire, même après l'appel à la fonction.
    Donc si on retourne un pointeur sur une constante, ça compilera et fonctionnera.
    Par contre si on retourne un pointeur sur une variable automatique déclarée dans la fonction (ex : char Msg[100];)
    ça plantera, puisque dans ce cas la mémoire est allouée dans la pile, et est libérée à la fin de la fonction.
    La solution est d'allouer la mémoire dans le tas (allocation dynamique avec malloc). Ici la mémoire restera réservée jusqu'au free.

    5. Est ce que l'affectation peut planter en cours d'exécution (si pas de mémoire disponible) et comment cela se passe ?
    Comme expliqué en (2), la mémoire est allouée au lancement du programme (pas de l'affectation de la constante).
    Donc si ça plante à cause d'insuffisance de mémoire ça surviendra au lancement, pas de l'affectation.

    En espérant avoir été clair.

  4. #4
    Modérateur
    Avatar de Obsidian
    Homme Profil pro
    Développeur en systèmes embarqués
    Inscrit en
    Septembre 2007
    Messages
    7 450
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 48
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : Développeur en systèmes embarqués
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Septembre 2007
    Messages : 7 450
    Par défaut
    En fait, d'une manière générale, c'est plus simple si tu considères (à juste titre) que le C n'a pas de type natif pour gérer les chaînes de caractères.

    De là, on peut se focaliser sur le fait que « char const * » est avant tout un pointeur et que celui-ci peut pointer n'importe quoi, indépendamment de sa cible.

  5. #5
    Membre émérite

    Homme Profil pro
    Directeur des systèmes d'information
    Inscrit en
    Septembre 2010
    Messages
    450
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Val d'Oise (Île de France)

    Informations professionnelles :
    Activité : Directeur des systèmes d'information

    Informations forums :
    Inscription : Septembre 2010
    Messages : 450
    Par défaut
    Bonjour,

    Je te suggère d'utiliser un type spécialisé d'une librairie pour les chaînes de caractères en C.

    Le char* du C est minimaliste, et n'est pas aisé à manipuler.

    J'ai écrit la page suivante de la wikiversité: http://fr.wikiversity.org/wiki/GLib/..._Types#GString
    La GString est assez user friendly, je te conseille d'y jeter un oeil.
    Si vous moinsez, merci de répondre pour argumenter!
    Ma présentation

  6. #6
    Modérateur

    Avatar de Bktero
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Juin 2009
    Messages
    4 492
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 37
    Localisation : France, Loire Atlantique (Pays de la Loire)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels

    Informations forums :
    Inscription : Juin 2009
    Messages : 4 492
    Billets dans le blog
    1
    Par défaut
    Merci bien pour vos réponses J'ai un peu de mal à voir l'intérêt profond de ce genre de variables. Ca viendra peut-être au détour d'un projet.


    @BlueMonkey :

  7. #7
    Modérateur
    Avatar de Obsidian
    Homme Profil pro
    Développeur en systèmes embarqués
    Inscrit en
    Septembre 2007
    Messages
    7 450
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 48
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : Développeur en systèmes embarqués
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Septembre 2007
    Messages : 7 450
    Par défaut
    Citation Envoyé par Bktero Voir le message
    Merci bien pour vos réponses J'ai un peu de mal à voir l'intérêt profond de ce genre de variables. Ca viendra peut-être au détour d'un projet.
    Si par « ce genre de variable », tu entends les pointeurs en général et les « char const * » en particulier, alors un pointeur contient l'adresse mémoire d'un objet d'un type donné, que ce soit un int, un char, un float ou éventuellement… un autre pointeur, qui à son tour pointe un autre objet. Type donné ou pas, d'ailleurs, dans le cas de void.

    Ensuite, à partir du moment où on a l'emplacement exact d'un de ces éléments en mémoire, il est très facile d'exploiter des « chaînes », que ce soit des chaînes de caractères, des chaînes d'entiers, ou autres puisqu'à partir du moment où l'on sait où se trouve le premier élément, il est trivial de déduire où se trouve le suivant : il suffit d'ajouter la taille de l'élément pointé à la valeur du pointeur.

  8. #8
    Membre très actif
    Homme Profil pro
    Étudiant
    Inscrit en
    Décembre 2009
    Messages
    172
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Décembre 2009
    Messages : 172
    Par défaut
    Bonjour,

    Citation Envoyé par Bktero Voir le message
    Merci bien pour vos réponses J'ai un peu de mal à voir l'intérêt profond de ce genre de variables. Ca viendra peut-être au détour d'un projet.
    Ou peut-être que tu ne les utilises pas dans un bon contexte. const c'est pour constant donc l'utiliser dans des allocations dynamique risque d'être problématique!

    Comme dit précédemment, lorsque tu fais :
    A la compilation, ton compilo fait 2 choses. Il place la chaine "salut!\n" dans une page NON MODIFIABLE (http://en.wikipedia.org/wiki/Paging) en mémoire (.data) et deuxièmement il déclare un pointeur vers l'adresse de cette chaine dans la partie "instructions" de ton exécutable (.text).

    Comme la chaine n'est pas modifiable (ce n'est même pas ton compilo ou le système qui t'en empêche mais le processeur lui même en quelque sorte), tu dois rassurer ton compilo avec un const char * pour qu'il sache que tu n'essayeras pas de la modifier (Regardes ce thread http://www.developpez.net/forums/d11...ause-segfault/). Bref je ne t'apprends rien, je pense que tu as compris comment ça marche je récapitulais juste.

    Maintenant concernant l'intérêt de ce genre de variable en lui même, un exemple simple :
    Imagines que tu veuille réutiliser tes messages d'erreur dans un autre module. Comment fait tu pour spécifier au compilo de ne pas re réserver la chaine "NONE" ou "LIBUSB_SUCCESS" lorsqu'il va générer son .o, ce qui risque de prendre encore plus de place en mémoire et t'obligerait à modifier tous tes modules (toutes tes sources) lorsque tu veux changer "NONE" par "RIEN"? Tu déclares un pointeur "const char *" qui pointe dessus dans ton module et tu fais un "extern" dans un autre.

    Ce n'est qu'un exemple d'utilisation, il y'en a d'autres. Grâce à ce genre de variable tu t'assures aussi que la personne qui code une autre partie du module n'essayeras pas de la modifier (imagines que le moindre bit changé fasse crasher une autre partie de ton code).

    Voilà j'espère t'avoir aidé si j'ai bien compris quel était la question.

    Cordialement

Discussions similaires

  1. Réponses: 22
    Dernier message: 03/01/2008, 22h42
  2. Utilisation des CONST
    Par Aragorn_destroy dans le forum Macros et VBA Excel
    Réponses: 1
    Dernier message: 22/06/2007, 16h45
  3. Utilisation des char[]
    Par Aradesh dans le forum Débuter
    Réponses: 16
    Dernier message: 15/12/2005, 09h45

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