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
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
Bonjour,
malloc permet aussi d'allouer beaucoup de mémoire, beaucoup plus que la pile ne le permet.
Publication : Concepts en C
Mon avatar : Glenn Gould
--------------------------------------------------------------------------
Une réponse vous a été utile ? Remerciez son auteur en cliquant le pouce vert !
et le nombre de variable dans la pile est egale au nombre de registre ?
Non,
Ca peut dépendre du processeur (et du compilateur)
ok et vous connaissez le nombre de variable que je peux stocker dans la pile avec gcc
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
28192 KiB
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)⊤ 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...
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
28184 KiB
Ceci dit on peut changer la taille de la pile via quelques appels système, sous GNU/Linux cela donne :
J'espère ne pas avoir dit trop de bêtises
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)⊤ 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; }
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 --
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)
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:
Ce code affichera 42.
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; }
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.
Le registre SS contient l'adresse du segment de pile courant et SP est l'adresse du sommet de la pile dans ce segment.et les registres du processeur contiennent les adresses des variables de la pile ?
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 :
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
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; }
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.
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
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.
bjr,
j'ai ecrit un petit programme pour tester la pile.
j'ai remarque qu à l execution le tableau de ma fonction f() n'etait pas perdu ?
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; }
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.j'ai remarque qu à l execution le tableau de ma fonction f() n'etait pas perdu ?
pourquoi ? est ce que ca vient du compilateur ?
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 !
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 :
le résultat chez moi est :
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; }
et non
Code : Sélectionner tout - Visualiser dans une fenêtre à part 4 5 6
Tu peux ne pas obtenir le même résultat, c'est pourquoi le comportement est dit indéfini.
Code : Sélectionner tout - Visualiser dans une fenêtre à part 1 2 3
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 --
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.
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.
Vous avez un bloqueur de publicités installé.
Le Club Developpez.com n'affiche que des publicités IT, discrètes et non intrusives.
Afin que nous puissions continuer à vous fournir gratuitement du contenu de qualité, merci de nous soutenir en désactivant votre bloqueur de publicités sur Developpez.com.
Partager