Forum Programmation.c Chaines constantes...

Posté par  .
Étiquettes : aucune
0
25
nov.
2004
Bonjour à tous :)

J'aimerais avoir une réponse définitive à une question idiote qui me taraude depuis quelque temps.

D'abord un petit code d'exemple :

hello.c :
-------------------------8<---------------------------------

#define CHAINE1 "coin coin !\n"
#define CHAINE2 "pan !\n"

int main(int argc, char **argv)
{
char *sChaine = NULL;

if (argc > 1)
{
sChaine = CHAINE1;
}
else
{
sChaine = CHAINE2;
}

printf(sChaine);

return 0;
}

-------------------------8<---------------------------------

Maintenant sa sortie, qui me semble en concordance avec le code.

jaguarwan@Jaguar:~$ gcc -Wall -ansi -pedantic hello.c -o gruik
jaguarwan@Jaguar:~$ ./gruik a
coin coin !
jaguarwan@Jaguar:~$ ./gruik
pan !

Toute se passe bien, gcc ne m'insulte pas, le comportement est apparemment fiable. Pourtant, on m'a dit que cela ne se faisait pas car "les chaînes n'étaient pas allouées et qu'en plus j'affectait la chaîne directement à un pointeur".

J'ai personnellement l'impression que le compilateur affecte simplement l'adresse de la chaîne constante (qu'il a alloué où bon lui semble) à mon pointeur, me permettant de l'afficher par la suite. Qu'en pensez-vous ?

Si vous pouviez me donner une URL avec l'explication détaillée de ce phénomène, je vous serais très reconnaissant :)

P.S:
(oui je sais, printf(CHAINEx); ça marche bien mais là n'est pas la question :)
  • # je ne fait que mon boulot ...

    Posté par  (site web personnel) . Évalué à 7.

    Comme je suis prof de C/UNIX, voici mon humble explication ...

    Dans un programme qui s'exécute (un process quoi), on distingue deux parties : statique et dynamique.

    Dans la partie dynamique on va trouver tes variables (*sChaine par ex) qui peuvent changer au cour de l'exécution (allocation, free, toussa ...)
    Dans la partie statique, on va trouver les variables et constantes dont la valeur a pu être définie au moment de la compilation (#define , chaines constantes : char *str="coin ! coin !\n", etc ...)
    La partie dynamique est evidement en R/W.
    La partie statique est en RO !

    donc faire sChaine = CHAINE1 affecte a un pointeur sur char une adresse pointant dans la partie statique de ton programme, donc un access que tu crois en R/W alors qu'il sera en fait en RO ! Une belle source de core dumps !
    Maintenant, si tu te contente de les afficher, aucun pb. par contre, essaye de faire un :
    sChaine = CHAINE1;
    sChaine[0] = sChaine[0] - 'a' + 'a'; // Met en majuscule la 1ere lettre de la chaine


    Ca plante aussi sec !
    • [^] # Re: je ne fait que mon boulot ...

      Posté par  (site web personnel) . Évalué à 4.

      arg... s/ + 'a'/ + 'A'/
    • [^] # Re: je ne fait que mon boulot ...

      Posté par  . Évalué à 6.

      d'ou l'interet d'utiliser des "const char * const" plutot que des #define :
      avec

      const char * const CHAINE1 ="coin coin !\n";
      const char * const CHAINE2 ="pan !\n";

      sans changer le reste du programe , on a :
      %gcc -ansi -pedantic helo.c -o gruik
      tt.c: In function `main':
      tt.c:12: warning: assignment discards qualifiers from pointer target type
      tt.c:16: warning: assignment discards qualifiers from pointer target type

      en c++:
      %g++ hello.cpp -o gruikcpp
      tt.cpp: In function `int main(int, char**)':
      tt.cpp:12: error: invalid conversion from `const char*' to `char*'
      tt.cpp:16: error: invalid conversion from `const char*' to `char*'


      Et si on transforme sChaine en const char * , on ne peux plus le modifier a moins de faire un cast explicitement.


      BTW autre avantage , au debuggage c'est plus facile car CHAINE1 est une vraie variable qu'on peut afficher.
  • # Autre chose

    Posté par  . Évalué à 9.

    Sans rapport avec ta question mais je me permets une remarque :

    printf(sChaine);


    n'est pas souhaitable. Il faudrait :

    printf("%s",sChaine);


    L'explication nous vient du manuel (cf man 3 printf) :

    Un code tel que printf(foo); indique souvent un bogue, car foo peut contenir un caractère %. Si foo vient d'une saisie non sécurisée, il peut contenir %n, ce qui autorise printf à écrire dans la mémoire, et crée une faille de sécurité.

Suivre le flux des commentaires

Note : les commentaires appartiennent à celles et ceux qui les ont postés. Nous n’en sommes pas responsables.