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 :

malloc dans main


Sujet :

C

  1. #1
    Membre averti Avatar de fantomas261
    Inscrit en
    Avril 2007
    Messages
    486
    Détails du profil
    Informations forums :
    Inscription : Avril 2007
    Messages : 486
    Points : 331
    Points
    331
    Par défaut malloc dans main
    bjr,
    j'ai appris l'utiliter d'utiliser malloc pour stocker des donnees en dehors de la pile dans une fonction, mais est t il utile d utiliser malloc dans le main ?
    si oui pourquoi ?
    merci

  2. #2
    Invité(e)
    Invité(e)
    Par défaut
    Bonjour,
    malloc permet aussi d'allouer beaucoup de mémoire, beaucoup plus que la pile ne le permet.

  3. #3
    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
    Citation Envoyé par fantomas261 Voir le message
    bjr,
    j'ai appris l'utiliter d'utiliser malloc pour stocker des donnees en dehors de la pile dans une fonction, mais est t il utile d utiliser malloc dans le main ?
    si oui pourquoi ?
    merci
    main() n'est qu'une fonction parmi les autres. Sa seule particularité est que le programme commence son exécution par elle.
    Les arguments qui justifient l'utilisation de malloc() (dont celui signalé par mabu) s'appliquent aussi bien à la fonction main().
    Publication : Concepts en C

    Mon avatar : Glenn Gould

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

  4. #4
    Membre averti Avatar de fantomas261
    Inscrit en
    Avril 2007
    Messages
    486
    Détails du profil
    Informations forums :
    Inscription : Avril 2007
    Messages : 486
    Points : 331
    Points
    331
    Par défaut
    et le nombre de variable dans la pile est egale au nombre de registre ?

  5. #5
    Invité(e)
    Invité(e)
    Par défaut
    Non,
    Ca peut dépendre du processeur (et du compilateur)

  6. #6
    Membre averti Avatar de fantomas261
    Inscrit en
    Avril 2007
    Messages
    486
    Détails du profil
    Informations forums :
    Inscription : Avril 2007
    Messages : 486
    Points : 331
    Points
    331
    Par défaut
    ok et vous connaissez le nombre de variable que je peux stocker dans la pile avec gcc

  7. #7
    Membre éprouvé Avatar de orfix
    Homme Profil pro
    Inscrit en
    Avril 2007
    Messages
    707
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Maroc

    Informations professionnelles :
    Secteur : High Tech - Produits et services télécom et Internet

    Informations forums :
    Inscription : Avril 2007
    Messages : 707
    Points : 1 132
    Points
    1 132
    Par défaut
    Déjà je ne sais pas si on peut parler de gcc dans ce cas, il me semble que ni le compilateur ni le langage ne rentre en jeu dans la détermination de la taille de la pile, c'est plus de l'ordre du Système d'exploitation mais, peut-être que je me trompe ?

    Je suppose que tu voulais dire « taille de la pile » et non « nombre de variable » puisque ça n'a pas beaucoup de sens.

    Pour déterminer la taille de la pile on peut faire comme suit (GNU/Linux uniquement) :
    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
     
    #include  <stdio.h>
    #include  <stdlib.h>
    #include <sys/time.h>
    #include <sys/resource.h>
     
    int main( void )
    {
    	struct rlimit rlim;
     
    	getrlimit(RLIMIT_STACK,&rlim);
    	printf("%lu KiB\n",rlim.rlim_cur/1024);
     
    	return 0;
    }
    Une autre façon portable, mais crados (provoquant volontairement un stack overflow) :
    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
     
    #include  <stdio.h>
    #include  <stdlib.h>
     
    #define  PRECISION (100)
     
    void foo(long unsigned bottom)
    {
    	static unsigned calls=0;
    	long unsigned top = (long unsigned)&top;
     
    	calls++;
    	if(calls%PRECISION == 0)
    	{
    		printf("%lu KiB\n", (bottom - top)/1024);
    	}
    	foo(bottom);
    }
     
    int main( void )
    {
    	long unsigned sp = (unsigned long)&sp;
     
    	foo(sp); /* 8184 */
     
    	return 0;
    }
    On se rapproche des 8192 KiB, il faut certainement rajouter la taille de l'enregistrement d'activation (est-ce le bon terme pour stack frame ? ) de printf etc...

    Ceci dit on peut changer la taille de la pile via quelques appels système, sous GNU/Linux cela donne :
    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
    34
    35
    36
     
    #include  <stdio.h>
    #include  <stdlib.h>
    #include <sys/time.h>
    #include <sys/resource.h>
     
    #define  PRECISION (100)
     
    void foo(long unsigned bottom)
    {
    	static unsigned calls=0;
    	long unsigned top = (long unsigned)&top;
     
    	calls++;
    	if(calls%PRECISION == 0)
    	{
    		printf("%lu KiB\n", ((bottom - top)/1024));
    	}
    	foo(bottom);
    }
     
    int main( void )
    {
    	long unsigned sp = (unsigned long)&sp;
    	struct rlimit rlim;
     
    	getrlimit(RLIMIT_STACK,&rlim);
    	printf("Current Stack Size : %lu KiB\n",rlim.rlim_cur/1024); /* 8192 */
    	rlim.rlim_cur *=2;	/* On DOUBLE la taille de la pile */
    	setrlimit(RLIMIT_STACK,&rlim);
    	printf("Changed to         : %lu KiB\n",rlim.rlim_cur/1024); /* 16384 */
    	/* Décommenter la ligne qui suit pour une vérification */
    	//foo(sp); /* 16373 KiB */
     
    	return 0;
    }
    J'espère ne pas avoir dit trop de bêtises
    To start press any key. (reading screen) Where's the "any" key? I see Esc, Catarl, and Pig Up. There doesn't seem to be any "any" key. Wo! All this computer hacking is making me thirsty. I think I'll order a Tab. (presses TAB key). -- HOMER --

  8. #8
    Membre averti Avatar de fantomas261
    Inscrit en
    Avril 2007
    Messages
    486
    Détails du profil
    Informations forums :
    Inscription : Avril 2007
    Messages : 486
    Points : 331
    Points
    331
    Par défaut
    ok pour la taille et les registres du processeur contiennent les adresses des variables de la pile ?
    une autre question hors sujet, j ai vu que tu déclarais des constantes symboliques avec des parenthèses ( exemple #define EOF (-1) ) pourquoi? (j'en vois l'utiliter pour des macros fonctons)

  9. #9
    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 519
    Points
    41 519
    Par défaut
    Quand c'est juste un nombre positif, ça ne sert pas à grand-chose, mais dès que c'est plus compliqué, ça peut s'avérer vital.

    Exemple classique:
    Code C : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    #include <stdio.h>
    #define SIX 1+5
    #define NINE 8+1
     
    int main(void)
    {
    	printf("SIX by NINE = %d", SIX * NINE);
    	return 0;
    }
    Ce code affichera 42.
    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.

  10. #10
    Membre chevronné
    Profil pro
    Inscrit en
    Août 2006
    Messages
    1 104
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Août 2006
    Messages : 1 104
    Points : 1 750
    Points
    1 750
    Par défaut
    et les registres du processeur contiennent les adresses des variables de la pile ?
    Le registre SS contient l'adresse du segment de pile courant et SP est l'adresse du sommet de la pile dans ce segment.
    Les variables locales sont empilées dans un ordre précis. Leur adresse, dans la pile est donc connue.
    Généralement, pour lire (ou écrire) dans une variable locale, on copie d'abord ESP dans un autre registre (EBP par exemble), puis on additionne une constante (qui correspond à l'adresse de la variable locale dans la pile), ce qui donne l'adresse de la variable en question. Pour lire sa valeur, on y accède via une instruction qui va bien.

    Par exemple, dans un programme totalement inutile comme celui-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
    22
    23
    24
    #include <stdlib.h>
    #include <stdio.h>
    #include <time.h>
     
    int fonction(int a, int b, int c)
    {
        int r;
        r=10*a+15*b+25*c;
        return r;
    }
    int main(void)
    {
        int r,a,b,c;
        srand (time (NULL));
     
        a=rand()%1000;
        b=rand()%1000;
        c=rand()%1000;
     
        r=fonction(a,b,c);
        printf("%d,%d,%d : %d\n",a,b,c,r);
     
        return EXIT_SUCCESS;
    }
    Le code assembleur généré donne, pour la fonction fonction ceci :

    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
    _fonction:
    LFB8:
    LVL0:
    	push	ebp
    LCFI0:
    	mov	ebp, esp ; on sauve ESP dans EBP
    LCFI1:
    	mov	eax, DWORD PTR [ebp+8] ; "a" est stocké à l'adresse EBP+8, on le met dans le registre EAX.
    	mov	edx, DWORD PTR [ebp+12] ; "b" est stocké à l'adresse EBP+12, on le met dans le registre EDX.
    	mov	ecx, DWORD PTR [ebp+16] ; "c" est stocké à l'adresse EBP+16, on le met dans le registre ECX.
    	.loc 1 6 0
    	lea	edx, [edx+edx*2]
    	lea	edx, [edx+edx*4]
    	lea	eax, [eax+eax*4]
    	lea	eax, [edx+eax*2]
    	lea	ecx, [ecx+ecx*4]
    	lea	ecx, [ecx+ecx*4]
    	add	eax, ecx
    	.loc 1 10 0
    	leave
    	ret
    ESP (registre qui contient l'adresse du sommet de la pile) est d'abord stocké dans EBP. Ensuite, pour traiter la variable "a", il faut la stocker dans un registre (EAX dans notre exemple). Pour cela, on lit l'adresse [EBP+8], là où est contenue cette valeur, puis on la met dans le registre EAX.

    Pour un programmeur C, c'est le compilo qui se charge de tout, c'est son boulot.
    C'est surtout important de savoir tout ça si on développe en assembleur, forcément.

  11. #11
    Membre averti Avatar de fantomas261
    Inscrit en
    Avril 2007
    Messages
    486
    Détails du profil
    Informations forums :
    Inscription : Avril 2007
    Messages : 486
    Points : 331
    Points
    331
    Par défaut
    bjr,
    j'ai ecrit un petit programme pour tester la pile.
    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
     
    #include <stdio.h>
    #include <stdlib.h>
     
    int *f()
    {
     int tab[] = {1,2,3};
     return tab ;
     
     }
     
     
    int main() {
     int * t = f();
     printf("%d %d %d\n",t[0],t[1],t[2]);
     return 0;
        }
    j'ai remarque qu à l execution le tableau de ma fonction f() n'etait pas perdu ?
    pourquoi ? est ce que ca vient du compilateur ?

  12. #12
    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
    j'ai remarque qu à l execution le tableau de ma fonction f() n'etait pas perdu ?
    pourquoi ? est ce que ca vient du compilateur ?
    Cela vient uniquement de ta malchance : la zone mémoire utilisée par tab n'a pas encore été réutilisé pour y mettre autre chose et cela semble marcher.
    En conclusion, le code est intrinsèquement vérolé et l'utiliser donnera des comportements totalement imprévisibles.
    Publication : Concepts en C

    Mon avatar : Glenn Gould

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

  13. #13
    Membre éprouvé Avatar de orfix
    Homme Profil pro
    Inscrit en
    Avril 2007
    Messages
    707
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Maroc

    Informations professionnelles :
    Secteur : High Tech - Produits et services télécom et Internet

    Informations forums :
    Inscription : Avril 2007
    Messages : 707
    Points : 1 132
    Points
    1 132
    Par défaut
    Comme l'explique diogene, cette zone mémoire n'a pas été réutilisée, d'ailleurs tu peut t'en rendre compte en faisant un appel à une fonction différente juste après le premier appel, comme ceci :
    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
     
    #include <stdio.h>
    #include <stdlib.h>
     
    int *f()
    {
    	int tab[] = {1,2,3};
    	return tab ;
    }
     
    int *ff()
    {
    	int tab[] = {4,5,6};
    	return tab ;
    }
     
    int main() 
    {
    	int *t = f();
     
    	ff();
    	printf("%d %d %d\n",t[0],t[1],t[2]);
     
    	return 0;
    }
    le résultat chez moi est :
    et non
    Tu peux ne pas obtenir le même résultat, c'est pourquoi le comportement est dit indéfini.
    To start press any key. (reading screen) Where's the "any" key? I see Esc, Catarl, and Pig Up. There doesn't seem to be any "any" key. Wo! All this computer hacking is making me thirsty. I think I'll order a Tab. (presses TAB key). -- HOMER --

  14. #14
    Membre averti Avatar de fantomas261
    Inscrit en
    Avril 2007
    Messages
    486
    Détails du profil
    Informations forums :
    Inscription : Avril 2007
    Messages : 486
    Points : 331
    Points
    331
    Par défaut
    est ce que la première variable stockée dans la pile à toujours la même adresse?

  15. #15
    Modérateur
    Avatar de Obsidian
    Homme Profil pro
    Développeur en systèmes embarqués
    Inscrit en
    Septembre 2007
    Messages
    7 369
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 47
    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 369
    Points : 23 623
    Points
    23 623
    Par défaut
    Citation Envoyé par fantomas261 Voir le message
    est ce que la première variable stockée dans la pile à toujours la même adresse?
    Il faut absolument que tu comprennes que sur les ordinateurs personnels domestiques, la pile est matérialisée par un segment d'espace en mémoire (comme un gros malloc()) dans lequel se déplace un pointeur de pile. En l'état, celui-ci se trouve dans un registre du processeur puisque la pile est exploitée par ledit micro-processeur, mais tu pourrais très bien faire ta propre pile en utilisant une variable.

    Le nombre d'objets que tu peux stocker dans ta pile ainsi que leur emplacement est donc directement fonction de l'emplacement du segment de mémoire consacré à cette pile et à sa taille. Il est également dépendant du nombre de fonctions que tu appelles successivement, spécialement dans le cas d'appels récursifs. Donc, rien ne te permet à l'avance de savoir où ces objets vont se trouver au final.

    Il n'y a que sur certains processeurs exotiques que l'on trouvait une pile réellement hardware, intégrée au micro-processeur lui-même et, par conséquence, très limitée. On en parlait sur ce fil.

  16. #16
    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 519
    Points
    41 519
    Par défaut
    Citation Envoyé par fantomas261 Voir le message
    est ce que la première variable stockée dans la pile à toujours la même adresse?
    Sur un système supportant l'Address Space Layout Randomization (ASLR), elle n'est jamais à la même adresse.

    Mais elle est toujours au même offset par rapport au pointeur de pile dans la fonction, pour un compilateur et des options de compilation données.
    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.

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

Discussions similaires

  1. Variable publique dans main ?
    Par Magicien d'Oz dans le forum Langage
    Réponses: 13
    Dernier message: 13/07/2006, 11h40
  2. [Debutant]Exception NoClassDefFoundError dans main
    Par Mystnux dans le forum Langage
    Réponses: 4
    Dernier message: 17/06/2006, 12h24
  3. utilisation de malloc dans un fichier
    Par nemesys971 dans le forum C
    Réponses: 10
    Dernier message: 09/05/2006, 17h33
  4. Réponses: 5
    Dernier message: 15/09/2005, 14h05
  5. Réponses: 6
    Dernier message: 15/09/2005, 14h04

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