logo Homepage
Pages: [1]
  Imprimer  
Auteur Fil de discussion: Pourquoi le programme fonctionne ?  (Lu 17341 fois)
Creaprog

Profil challenge

Classement : 4748/54445

Néophyte
*
Hors ligne Hors ligne
Messages: 4


Voir le profil
« le: 13 Décembre 2016 à 12:48:28 »

Bonjour,

Je rencontre un problème, une incompréhension en C.

Code:
int main(void)
{
    char *user;
    user = "toto";
    puts(user);
}

Le code fonctionne, mais je ne comprend pas. char *user permet de stocker l'adresse d'un char. Ensuite on essaye de mettre 4bytes dans l'adresse d'un char...

Voici pour moi un code qui marche (oui c'est chelou une correction d'un code qui marche...)

Code:
int main(void)
{
    char *user = "toto";
    puts(user);
}

Cela fait 8 mois que je n'ai pas fait de C donc rester cool avec moi  

Je suis sur mon Mac et je n'ai pas de Linux actuellement sous la main, impossible de faire un valgrind  
Journalisée

Fan de Pixis
Creaprog

Profil challenge

Classement : 4748/54445

Néophyte
*
Hors ligne Hors ligne
Messages: 4


Voir le profil
« #1 le: 13 Décembre 2016 à 17:51:57 »

Merci pixis. Si je ne dit pas de connerie.

Dans le premier cas, on créer un pointeur de type char, ensuite il créer la chaine de caractère.
Dans le deuxième cas, on sa créer direct la chaine de caractère.
Journalisée

Fan de Pixis
dionosis

Profil challenge

Classement : 29/54445

Membre Junior
**
Hors ligne Hors ligne
Messages: 94


Voir le profil
« #2 le: 13 Décembre 2016 à 18:40:35 »

Salut,

En fait tes deux extraits de code sont strictement équivalents.
Le type de la variable 'user' c'est (char*) et non pas (char).

C'est probablement plus clair comme ça :

Code:
void foo()
{
    typedef char* pChar

    pChar user;
    user = "toto";
    puts(user);
}

Donc tu vois bien que le faire sur une ligne ou sur deux revient au même.

Quant au fait que tu puisses utiliser ce genre d'égalité, c'est simplement une facilité offerte par le compilateur.
Ce qu'il se passe derrière c'est ça :

Citation
void foo()
{
    static char _totoString[4+1] = "toto";   // 8 en réalité pour alignement, dans le tas (section datas initialisées du binaire loadé), donc scope local mais lifetime global, et initialisé au loadtime et non pas au runtime

    char *user;
    user = &_totoString[0];
    puts(user);
}

Ca sera sûrement plus parlant comme ça.

++

Ps: Je ne vois pas la réponse de pixis dont tu parles ?!
« Dernière édition: 13 Décembre 2016 à 18:45:43 par dionosis » Journalisée
the lsd
Administrateur

Profil challenge

Classement : 190/54445

Membre Héroïque
*****
Hors ligne Hors ligne
Messages: 3096

poulping for fun & profit


Voir le profil WWW
« #3 le: 13 Décembre 2016 à 19:34:06 »

La réponse de pixis était sur irc, j'ai dit que ça serait cool de l'écrire sur le forum une fois qu'ils auraient fini d'en parler, mais j'ai pas préciser comment l'écrire ^^'

Par contre, je suis d'accord avec dionosis, mais de ce que j'en ai compris sur irc, les deux codes n'étaient pas équivalent et l'un d'eux aurait pas du fonctionner (pas suivi tout l'affaire non plus)

Enjoy

The lsd
Journalisée

Newbie Contest Staff :
The lsd - Th3_l5D (IRC)
Statut :
Administrateur
Citation :
Cartésien désabusé : je pense, donc je suis, mais je m'en fous !
dionosis

Profil challenge

Classement : 29/54445

Membre Junior
**
Hors ligne Hors ligne
Messages: 94


Voir le profil
« #4 le: 13 Décembre 2016 à 21:07:02 »

Re,

Dac, ma réponse est correcte pour le code cité dans le post original, mais je vais tacher d'énumérer les autres différents cas de figure pour clarifier.



Le code suivant (cas 1) :

Code:
char *user;

void foo()
{
    user = "toto";
    puts(user);
}

équivaut à :

Code:
static char _totoString[4+1] = "toto";   // 8 en réalité pour alignement, dans un TAS (section datas INITIALISEES du binaire loadé), scope GLOBAL et lifetime GLOBAL, initialisé au LOADTIME
static char *user;   // pointeur donc 4 ou 8 selon si 32 ou 64 bits, dans un TAS (section datas NON INITIALISEES du binaire loadé), scope GLOBAL et lifetime GLOBAL, initialisé au RUNTIME

void foo()
{
    user = &_totoString[0];   // RUNTIME
    puts(user);
}



Le code suivant (cas 2) :

Code:
char *user = "toto";

void foo()
{
    puts(user);
}

équivaut à :

Code:
static char user[4+1] = "toto";   // 8 en réalité pour alignement, dans un TAS (section datas INITIALISEES du binaire loadé), scope GLOBAL et lifetime GLOBAL, initialisé au LOADTIME

void foo()
{
    puts(user);
}



Le code suivant (cas 3) :

Code:
void foo()
{
    char user[4+1] = "toto";
    puts(user);
}

équivaut à (Edit2: en 32 bits, si la version 64 bits vous intéresse faites le moi savoir) :

Code:
void foo()
{
    char user[4+1];   // 8 en réalité pour alignement, dans la PILE, scope LOCAL et lifetime LOCAL, initialisé au RUNTIME
    register unsigned int *pUser;   // pointeur donc 4 ou 8 selon si 32 ou 64 bits, dans un REGISTRE, scope LOCAL et lifetime LOCAL, initialisé au RUNTIME

    pUser = (unsigned int *)&user[0];   // RUNTIME
    *pUser = 0x6F746F74;   // dans le cas d'une architecture low-endian
    pUser++;   // arithmétique pointeurs donc +4 ici en 32 bits
    *pUser = 0;   // null terminated

    puts(user);
}

MAIS pourra si la chaîne est trop longue et selon l'optimisation être traduit vers justement le cas 0 de ma réponse initiale !

C'est ce cas qui est ambigü.



Le code suivant (cas 4) :

Code:
char user[4+1];

void foo()
{
    user = "toto";
    puts(user);
}

et le code suivant (cas 5) :

Code:
void foo()
{
    char user[4+1];
    user = "toto";
    puts(user);
}

sont incorrects. Il faudra employer une méthode/fonction de copie, ou bien le faire manuellement.



Et user[] sera interprété par le compilateur comme *user dans le cadre de ce qui nous intéresse ici.

Edit1: On m'a demandé de vérifier sous gcc, et donc en fait user[] :
 - sous visual se comporte comme le cas 0 de ma réponse initiale (*user, conforme)
 - sous gcc/mingw se comporte comme le cas 3 de cette réponse ci (user[n_auto], non conforme, et donc ambigu aussi)



Arf, ça m'apprendra à vouloir répondre en 5 minutes quand c'est merdeux comme ça.

++
« Dernière édition: 15 Décembre 2016 à 02:01:10 par dionosis » Journalisée
pixis
Administrateur

Profil challenge

Classement : 16/54445

Membre Héroïque
*****
Hors ligne Hors ligne
Messages: 664


Voir le profil WWW
« #5 le: 13 Décembre 2016 à 23:49:43 »

Avec la première réponse, dionosis avait résumé grosso modo ce que j'avais raconté sur IRC
Journalisée

Newbie Contest Staff :
Pixis
Statut :
Administrateur
Blog :
hackndo
the lsd
Administrateur

Profil challenge

Classement : 190/54445

Membre Héroïque
*****
Hors ligne Hors ligne
Messages: 3096

poulping for fun & profit


Voir le profil WWW
« #6 le: 14 Décembre 2016 à 11:41:10 »

En tout cas, GG pour ta réponse de ouf dionosis !

Enjoy

The lsd
Journalisée

Newbie Contest Staff :
The lsd - Th3_l5D (IRC)
Statut :
Administrateur
Citation :
Cartésien désabusé : je pense, donc je suis, mais je m'en fous !
Creaprog

Profil challenge

Classement : 4748/54445

Néophyte
*
Hors ligne Hors ligne
Messages: 4


Voir le profil
« #7 le: 14 Décembre 2016 à 16:56:25 »

architecture low-endian == Endianness ?
Code:
*pUser = 0x6F746F74;   // dans le cas d'une architecture low-endian
Comment il a deviner l'adresse au pif ?
Journalisée

Fan de Pixis
dionosis

Profil challenge

Classement : 29/54445

Membre Junior
**
Hors ligne Hors ligne
Messages: 94


Voir le profil
« #8 le: 14 Décembre 2016 à 20:26:01 »

Salut,

Citation de: Creaprog
Comment il a deviner l'adresse au pif ?
- '*pUser' est la valeur pointée, 'pUser' est le pointeur. Go cours C sur les pointeurs (en fait je crois que c'est ça ton problème à la base).
- "toto" en hexa c'est "\x74\x6F\x74\x6F" (+ "\x00" final). Inversé en low-endian. Go cours C sur les chaînes null terminated + cours d'architecture.

++
Journalisée
Creaprog

Profil challenge

Classement : 4748/54445

Néophyte
*
Hors ligne Hors ligne
Messages: 4


Voir le profil
« #9 le: 14 Décembre 2016 à 21:49:01 »

Salut,

Merci de ton message j'ai relu encore et encore. Merci de m'avoir mit en pls. J'ai fais avant du C mais en bâclant, aujourd'hui je souhaite le reprendre avec des bases solides.
Journalisée

Fan de Pixis
dionosis

Profil challenge

Classement : 29/54445

Membre Junior
**
Hors ligne Hors ligne
Messages: 94


Voir le profil
« #10 le: 15 Décembre 2016 à 02:03:21 »

Salut,

De rien
Bonne continuation.

++
Journalisée
Pages: [1]
  Imprimer  
 
Aller à: