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 :

Passage d'arguments Pile/Memoire ?


Sujet :

C

  1. #1
    Membre confirmé
    Profil pro
    Inscrit en
    Août 2006
    Messages
    193
    Détails du profil
    Informations personnelles :
    Âge : 36
    Localisation : Tunisie

    Informations forums :
    Inscription : Août 2006
    Messages : 193
    Par défaut Passage d'arguments Pile/Memoire ?
    Hola ,
    la notion de la pile liberée n'est pas assez claire dans ma tête...
    Bon prenant le fameux code d'échange de 2 variables
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
     
    void echange ( int i ; int j) 
     { 
       int tampon;
       tampon=i ;
       i=j ;
       j=tampon ;
    D'après ce que je sais
    Lors d'un appel à cette fonction : echange(a,b) les contenus de i et j sont echangés puis la pile(ou se situe les variables locales) est liberée sans modifier a et b

    Or lorsque on appelle la fonction par echange(&a,b&) tout se passe bien puisque on les a transmis leurs adresses
    quelqu'un pourrait m'expliquer qu'est ce que ce passe au niveau de la memoire ainsi que la pile...(je veux aller en profondeur )
    Merci d'avance pour vos réponses

  2. #2
    Membre chevronné
    Inscrit en
    Août 2004
    Messages
    556
    Détails du profil
    Informations forums :
    Inscription : Août 2004
    Messages : 556
    Par défaut
    Bon, je vais zapper ton problème de syntaxe, mais voilà comment ça se passe:

    Imagine que tu as une variable nommé A et admettons qu'il se trouve à l'adresse 1.

    Lorsque tu passes cette variable à une fonction, par valeur:

    Le contenu de l'adresse 1 (c'est à dire la variable A) est copié dans la pile et le processeur travaille donc sur cette copie: les modifications sur cette copie ne sont donc pas répercutés sur le contenu de l'adresse 1.

    Lorsque tu passes cette variable par référence:

    Il n'y a pas de copie (en réalité, c'est l'adresse qui est copiée dans la pile), le processeur travaille directement sur l'adresse 1. Les modifications seront donc répercutés sur la variable A.

  3. #3
    Expert éminent
    Avatar de Médinoc
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Septembre 2005
    Messages
    27 395
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 41
    Localisation : France

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Septembre 2005
    Messages : 27 395
    Par défaut
    Partons d'un code simple:
    Code C : 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
    void echange ( int *pi,  int *pj) 
    { 
    	int tampon;
    	tampon = *pi;
    	*pi = *pj ;
    	*pj = tampon;
    }
     
    int main(int argc, char *argv[])
    {
    	int a=1, b=2;
    	/* On se moque des warnings "paramètre non-référencé" */
     
    	echange(&a, &b);
    	return 0;
    }
    Ici, quand on est dans la fonction, la pile doit contenir, dans l'ordre:
    • argv
    • argc
    • Adresse de retour pour main() (retourne quelque part)
    • Registres sauvegardés par main() (s'il y en a)
    • a et b (l'ordre est au choix du compilateur)
    • Adresse de b
    • Adresse de a
    • Adresse de retour depuis echange() (retourne dans main())
    • Registres sauvegardés par echange() (s'il y en a)
    • tampon
    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.

  4. #4
    Membre confirmé
    Profil pro
    Inscrit en
    Août 2006
    Messages
    193
    Détails du profil
    Informations personnelles :
    Âge : 36
    Localisation : Tunisie

    Informations forums :
    Inscription : Août 2006
    Messages : 193
    Par défaut
    Merci pour vos réponses )

  5. #5
    Membre chevronné Avatar de Lavock
    Profil pro
    Inscrit en
    Octobre 2009
    Messages
    560
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Octobre 2009
    Messages : 560
    Par défaut
    C'est un peu plus compliqué... Il faut différencier pile et registre. Le mieux; si tu veux vraiment comprendre, c'est de regarder des cours d'assembleurs (évite les architecture compliqué comme x86, tourne toi plutôt vers de l'arm).

    En gros, lors de l'appel de la fonction, tu vas empilé A et B et passez dans le registre leurs adresses, ainsi que le retour vers le main, et aller à ta fonction.

    Ensuite, la fonction va faire tes opérations (chargé A et B depuis leur adresse et swapper les valeur) et retouner dans le main.

    Celui-ci va dépiler les valeurs et OH ! Miracle, les valeur de A et B auront était changé.

  6. #6
    Expert éminent
    Avatar de Médinoc
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Septembre 2005
    Messages
    27 395
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 41
    Localisation : France

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Septembre 2005
    Messages : 27 395
    Par défaut
    Le passage de paramètres en C sur un x86 se fait traditionnellement par la pile (du moins, sous Windows, et il me semble que sous nux aussi). Le passage par registres est une optimisation.

    Même en x86-64, où les 4 premiers paramètres sont passés par registre, on réserve la place pour eux sur la pile.

    PS: Je ne qualifierais pas le x86 de "compliqué", surtout si on se limite aux registres du 8086: Le 8086 est une bonne machine à pile avec peu de registres, ce qui illustre bien le cas général du C.
    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.

  7. #7
    Membre chevronné Avatar de Lavock
    Profil pro
    Inscrit en
    Octobre 2009
    Messages
    560
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Octobre 2009
    Messages : 560
    Par défaut
    Citation Envoyé par Médinoc Voir le message
    Même en x86-64, où les 4 premiers paramètres sont passés par registre, on réserve la place pour eux sur la pile.
    Il me semblait que il était de même pour les x86-32.

  8. #8
    Expert éminent
    Avatar de Médinoc
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Septembre 2005
    Messages
    27 395
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 41
    Localisation : France

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Septembre 2005
    Messages : 27 395
    Par défaut
    En 32 bits, il y a un nombre assez impressionnant de conventions d'appel.
    • Sous Windows, sont standardisées les conventions "__cdecl" (C) et "__stdcall" (Convention standard Windows pour les DLLs). Les deux passent leurs paramètres sur la pile, la différence est qui la nettoie (__cdecl donne cette responsabilité à la fonction appelante, pour permettre l'appel de fonctions comme printf(), tandis que __stdcall place le nettoyage à la charge de la fonction appelée).
    • Divers compilateurs ont une convention "__fastcall" qui passe certains paramètres par registre, mais le __fastcall de Microsoft est différent de celui de Borland.
    • Microsoft possède aussi une convention "thiscall" utilisée pour les instances de classes C++ (sauf les classes COM qui utilisent __stdcall), qui passe this dans un registre et le reste sur la pile, nettoyage par fonction appelée (sauf pour les fonctions comme printf, qui sont en __cdecl à la place).
    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.

  9. #9
    Membre confirmé
    Profil pro
    Inscrit en
    Août 2006
    Messages
    193
    Détails du profil
    Informations personnelles :
    Âge : 36
    Localisation : Tunisie

    Informations forums :
    Inscription : Août 2006
    Messages : 193
    Par défaut
    Donc si j'ai bien compris il faut que je passe à l'assembleur pour comprendre en profondeur ce qui se passe au niveau de (l'architecture interne de mon ordinateur)...est ce que c'est évident que je comprenne la notion de la compilation en passant par le langage bas niveau si c'est le cas je suis partant pour le X86 quelqu'un parmi vous auraient des cours pour moi
    ça sera sympa
    Merci infiniment les gars...
    Une question :
    quelle est la différence entre le passage par référence et le passage par adresse (qui utilise la notion du pointeur) je sais qu'il y'a une différence au niveau de la déclaration de la fonction ainsi que l'appel mais tout de même je ne crois pas que j'ai bien compris la différence

  10. #10
    Rédacteur
    Avatar de 3DArchi
    Profil pro
    Inscrit en
    Juin 2008
    Messages
    7 634
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2008
    Messages : 7 634
    Par défaut
    Citation Envoyé par WhiteTigerZ Voir le message
    Donc si j'ai bien compris il faut que je passe à l'assembleur pour comprendre en profondeur ce qui se passe au niveau de (l'architecture interne de mon ordinateur
    Non. Parler de registre à ce moment n'était qu'une erreur qui ne fait qu'introduire de la confusion. La bonne explication est celle de Médinoc.

  11. #11
    Membre chevronné Avatar de Lavock
    Profil pro
    Inscrit en
    Octobre 2009
    Messages
    560
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Octobre 2009
    Messages : 560
    Par défaut
    Oui, ça aide forcément, même si je me suis planté pour les registres. Il semble que seul fastcall et thiscall utilise les registres en x86-32.

    -> Compilation = transformation en assembleur...

    Une fois en assembleur, le pointeur c'est une variable enregistré avec une adresse, alors que pour une ref; c'est directement la variable référencé. Et encore, ça dépend de l'optimisation de ton compilo...

  12. #12
    Rédacteur
    Avatar de 3DArchi
    Profil pro
    Inscrit en
    Juin 2008
    Messages
    7 634
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2008
    Messages : 7 634
    Par défaut
    Citation Envoyé par Lavock Voir le message
    Oui, ça aide forcément, même si je me suis planté pour les registres. Il semble que seul fastcall et thiscall utilise les registres en x86-32.
    Le choix du passage par registre ou par pile est une choix du compilateur.
    Citation Envoyé par Lavock Voir le message
    -> Compilation = transformation en assembleur...
    Va falloir réviser tes cours.
    Citation Envoyé par Lavock Voir le message
    Une fois en assembleur, le pointeur c'est une variable enregistré avec une adresse, alors que pour une ref; c'est directement la variable référencé. Et encore, ça dépend de l'optimisation de ton compilo...

  13. #13
    Expert éminent
    Avatar de Médinoc
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Septembre 2005
    Messages
    27 395
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 41
    Localisation : France

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Septembre 2005
    Messages : 27 395
    Par défaut
    Citation Envoyé par Lavock Voir le message
    Une fois en assembleur, le pointeur c'est une variable enregistré avec une adresse, alors que pour une ref; c'est directement la variable référencé. Et encore, ça dépend de l'optimisation de ton compilo...
    Une ref en paramètre, c'est exactement un pointeur déguisé.
    C'est seulement une ref dans le même bloc qui désigne la variable elle-même.

    Citation Envoyé par 3DArchi Voir le message
    Le choix du passage par registre ou par pile est une choix du compilateur.
    Il y a des conventions, quand même, comme je l'ai dit plus haut.
    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.

  14. #14
    Rédacteur
    Avatar de 3DArchi
    Profil pro
    Inscrit en
    Juin 2008
    Messages
    7 634
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2008
    Messages : 7 634
    Par défaut
    Citation Envoyé par Médinoc Voir le message
    Il y a des conventions, quand même, comme je l'ai dit plus haut.
    Oui. Ce que je voulais dire c'est que ces conventions ne relèvent pas du langage mais de la cible, et en cela ils sont le choix du compilateur, non ? Je ne pense pas que la façon de passer les paramètres soit décrite dans la norme C (ou C++).

  15. #15
    Expert éminent
    Avatar de Médinoc
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Septembre 2005
    Messages
    27 395
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 41
    Localisation : France

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Septembre 2005
    Messages : 27 395
    Par défaut
    Je pense que tu as raison.
    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.

  16. #16
    Rédacteur
    Avatar de 3DArchi
    Profil pro
    Inscrit en
    Juin 2008
    Messages
    7 634
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2008
    Messages : 7 634
    Par défaut
    Citation Envoyé par Médinoc Voir le message
    Une ref en paramètre, c'est exactement un pointeur déguisé.
    C'est seulement une ref dans le même bloc qui désigne la variable elle-même.
    Et encore, en mode debug (si ça un sens de comparer en mode debug), l'ASM généré par Visual Express semble indiquer que pointeurs et références sont gérés de façon identique :
    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
    struct A
    {
       int i;
    };
     
    int main()
    {
       A a;
       a.i=0;
       A *pa(&a);
       pa->i=1;
       A &ra(a);
       ra.i = 2;
       return 0;
    }
    Code ASM : 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
    ;int main()
    ;{
    	push        ebp  
    	mov         ebp,esp 
    	sub         esp,0Ch 
    ;   A a;
    ;   a.i=0;
    	mov         dword ptr [a],0 
    ;   A *pa(&a);
    	lea         eax,[a] 
    	mov         dword ptr [pa],eax 
    ;   pa->i=1;
    	mov         ecx,dword ptr [pa] 
    	mov         dword ptr [ecx],1 
    ;   A &ra(a);
    	lea         edx,[a] 
    	mov         dword ptr [ra],edx 
    ;   ra.i = 2;
    	mov         eax,dword ptr [ra] 
    	mov         dword ptr [eax],2 
    ;   return 0;
    	xor         eax,eax 
    }
    Je ne connais pas très bien l'assembleur, mais il semble bien que le code généré est sensiblement le même.

  17. #17
    Expert éminent
    Avatar de Médinoc
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Septembre 2005
    Messages
    27 395
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 41
    Localisation : France

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Septembre 2005
    Messages : 27 395
    Par défaut
    Y'a un problème dans ce code assembleur: je ne vois pas où est initialisé a, alors qu'il doit pointer quelque part sur la pile...
    Edit: Pareil pour pa et ra, en fait. Je pense que ce sont des defines sur "EBP+valeur"...
    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.

  18. #18
    Membre chevronné Avatar de Lavock
    Profil pro
    Inscrit en
    Octobre 2009
    Messages
    560
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Octobre 2009
    Messages : 560
    Par défaut
    Citation Envoyé par 3DArchi Voir le message
    Va falloir réviser tes cours.
    Je crois pas non...
    Un appelle a gcc ou g++ ->
    Precompilation (include, macro, etc...) (gcc/g++)
    Compilation(transformation en assembleur) (gcc/g++)
    Assemblage (via un assembleur)(as)
    Linkage (via un linker).(ld)

    Citation Envoyé par Médinoc Voir le message
    Une ref en paramètre, c'est exactement un pointeur déguisé.
    C'est seulement une ref dans le même bloc qui désigne la variable elle-même.
    Oui, c'est parfois juste un peu différent lorsqu'on le passe en param -> il peut y avoir optimisation dans certain cas sur une ref d'un type de base (peut-être qu'en fastcall d'ailleurs, j'ai jamais trop regarder les conventions d'appel).
    En tout cas, c'est ce qu'il m'avait semblé en retirer des lectures de compilation diverse de gcc...

  19. #19
    Expert éminent
    Avatar de Médinoc
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Septembre 2005
    Messages
    27 395
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 41
    Localisation : France

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Septembre 2005
    Messages : 27 395
    Par défaut
    Citation Envoyé par Lavock Voir le message
    Je crois pas non...
    Un appelle a gcc ou g++ ->
    Precompilation (include, macro, etc...) (gcc/g++)
    Compilation(transformation en assembleur) (gcc/g++)
    Assemblage (via un assembleur)(as)
    Linkage (via un linker).(ld)
    C'est ce qui est apparent, mais à ma connaissance, la plupart des bons compilos sautent l'étape "code source assembleur" et assemblent directement, ne générant un "code source assembleur" que sur demande (et encore, c'est généralement plus un "listing assembleur" qu'un "code source", vu qu'il peut contenir un dump hexadécimal du code assemblé)
    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.

  20. #20
    Membre chevronné Avatar de Lavock
    Profil pro
    Inscrit en
    Octobre 2009
    Messages
    560
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Octobre 2009
    Messages : 560
    Par défaut
    Je dis pas, c'est même pour l'optimisation que c'est fait comme ça... Mais stricto sensu c'est de la transformation en assembleur.

Discussions similaires

  1. passage d'argument sur l'imprimante
    Par linux dans le forum Général JavaScript
    Réponses: 8
    Dernier message: 07/10/2005, 16h25
  2. [JAVASCRIPT] passage d'argument à une fonction
    Par LE NEINDRE dans le forum Général JavaScript
    Réponses: 6
    Dernier message: 03/06/2005, 18h17
  3. [TASM] Passage d'argument à une macro
    Par sorry60 dans le forum Assembleur
    Réponses: 13
    Dernier message: 23/04/2005, 18h22
  4. [web] passage d'arguments à un CGI
    Par ma2th dans le forum Web
    Réponses: 4
    Dernier message: 20/08/2004, 12h18
  5. passage d'argument à la procédure main ()
    Par Zazeglu dans le forum C
    Réponses: 5
    Dernier message: 01/09/2003, 19h59

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