begin process at 2012 02 17 11:36:10
  Trouver un code source :
 
dans
 
Accueil > 

Tutoriels

 > 

Tutoriaux

 > ByRef et ByVal sans douleur

ByRef et ByVal sans douleur


 Information sur le tutoriel

Note :
Aucune note

 Description

Devant la confusion sur le sujet de ByRef et ByVal, j'ai décidé d'expérimenter un peu et de faire le débrousaillage.

Tutorial

ByRef et ByVal sans douleur


Devant la confusion sur le sujet de ByRef et ByVal, j'ai décidé d'expérimenter un peu et de faire le débrousaillage.

Voici les résultat de mes tests. Seuls les tests ayant donnés des résultats pertinents sont notés ici.

Le fait que l'appel soit une Function ou une Sub ne fait pas de différence puisque les variables examinées sont les valeurs transmises. Le comportement des valeurs retournées par une fonction est bein connu.

Tout d'abord, j'ai utilisé deux Sub type.

Private Sub CallSubByVal(ByVal nInt as Integer)

nInt = nInt * 10

End Sub

Private Sub CallSubByRef(ByRef nInt as Integer)

nInt = nInt * 10

End Sub

Examinons les résultats:

Dim nVal as Integer

nVal=10

CallSubByVal nVal

Debug.Print nVal : 10

nVal=10

CallSubByRef nVal

Debug.Print nVal : 100

Pas de surprise.

Mais lisez. Et voyez l'effet des parenthèses.

nVal=10

CallSubByRef (nVal)

Debug.Print nVal : 10

Ces parenthèses force le passage ByVal même si elle est spécifié ByRef.

Continuons.

Certains utilisent la convention "Call FunctionName..." dans le code.

Voyons l'effet.

nVal=10

Call CallSubByRef (nVal)

Debug.Print nVal : 100

Le mot-clé "Call" nécessite l'utilisation des parenthèses pour encadrer la valeur passée.

Pour avoir à nouveau l'effet parenthèses, il faut les doubler.

nVal=10

Call CallSubByRef ((nVal))

Debug.Print nVal : 10

J'èspère que ces éclaicissements pourront vous être utiles

Commentaires

Commentaire de ghuysmans99 le 17/06/2009 21:07:31

Intéressant, d'autant plus que peu de monde le sait (et je n'en faisais pas partie).

Commentaire de Renfield le 18/06/2009 07:04:52 administrateur CS

la raison en est fort simple.

en placant des parenthèses, notre expression est a évaluer. bien que très simple, cette expression n'a plus de lien avec nVal.

ça saute plus aux yeux si l'on fait par exemple:

CallSubByRef nVal * 1



mais effectivement, il peut être utile de préciser. tuto utile, donc.

Commentaire de oommeeggaa3d le 19/06/2009 14:14:05

le point important à retenir est donc que sans utilisation de "call", il faut bien penser à ne pas mettre de parenthèses ensuite.
merci de cette éclaircissement, certes logique, mais auquel je n'aurais pas pensé d'emblée.

Commentaire de us_30 le 20/06/2009 12:34:56

Cela mérite bien un 10/10...

Personnellement, j'évite au maximum ByRef pour deux raisons :
1. Cela veut aussi dire, en règle générale, qu'on aurait pu coder directement la Sub (ou Function) directement dans le programme principal...
2. Si la Sub (ou Function) est intéressant à coder séparément, elle doit être réutilisable pour un autre programme, et donc pour garder sa généralité il est préférable d'avoir ByVal pour des raisons pratiques évidentes...

nota : je dis, "j'évite au maximum ByRef", pourtant parfois je l'utilise tout même... je n'exprime pas un dogme...

Amicalement,
Us.

Commentaire de reacen le 23/06/2009 11:12:04


J'ai toujours pas compris le rôle de ByRef  et ByVal ? Quelqu'un peut m'expliquer rapidement ? :o

Et pourquoi dans certains codes source je trouve:

Call Function ?  pourquoi "Call" ?

Commentaire de bitshifter le 23/06/2009 19:06:06

ByVal signifie qu'une copie locale d'une valeur est manipulée par la function.
La valeur passée dans la function n'est pas modifiée.

ByRef passe l'addresse de la variable.
On note que tout object (controls ou tableau (array) ou object créé par l'instantiation d'une classe) "doit" être passé ByRef.
Ce qui signifie que tout changement fait à cette variable/object dans la function s'applique à la variable passée par la function.

Voir le tutorial pour les effets.

Commentaire de MadM@tt le 06/07/2009 11:32:06

US_30 > Pas d'accord avec toi :)
J'utilise autant que possible ByRef pour des raisons de rapidité et d'encombrement mémoire. Un ByVal crée une nouvelle variable à chaque appel de la fonction...

"Cela veut aussi dire, en règle générale, qu'on aurait pu coder directement la Sub (ou Function) directement dans le programme principal" > Oui mais une fonction a aussi un sens sémantique, pas uniquement pratique.

Concernant le tuto, je ne connaissais pas du tout ce comportement (qui est logique après les explications de Renfield), très bonne info.

Commentaire de MadM@tt le 06/07/2009 11:32:45

PS : les notes ne sont pas prises en compte ?

Commentaire de bitshifter le 06/07/2009 15:27:41

Call est une convention un peu obsolete mais conservée pour des raisons de compatibilité.

Call FunctionName(var) necessite les parenthèses et empêche d'obtenir la valeur de retour.

Comparer avec MaVar = FunctionName ( var)

Voila.

Et mettez donc une note.

Commentaire de jibob le 06/07/2009 19:35:28

Pour comprendre le pourquoi de ces 2 modes, il faut appréhender la notion de pointeur.
La mémoire est adressée par le processeur comme un suite d'adresses, chacune étant codée sur une valeur de 32 bits.
Ces adresses sont virtuelles et sont délivrées par le système d'exploitation au niveau du processus, mais elles correspondent à un emplacement physique de l'espace adressable du processeur ou l'on trouve la mémoire hardware.

Le pointeur est une valeur numérique codée sur 32 bits, mais dont la valeur n'est valable que pour un contexte donné.
Une variable est en réalité adressée par un pointeur 32 bits, même si pour la facilité l'on va utiliser la variable elle-même plutôt que son pointeur associé.
Dans bien des cas, ce pointeur prend la forme d'un des registres du processeur (exemple: EBP, EBX, ESI, EDI) plus d'un déplacement optionnel (offset 32 bits), ou d'une combinaison numérique de registres.

Cet adressage indexé est particulièrement utile lorsqu'il s'agit d'accèder à une structure ou à un objet.

Dans le cas de passage d'argument par BYVAL, les données sont intégralement recopiées dans la pile du processus, ce qui peut représenter un gaspillage, même si ces données ne sont allouées que temporairement.

Dans le cas de passage d'argument par BYREF, seul le pointeur sur cette donnée est recopié dans la pile et ceci offre l'avantage à la fonction appelée de modifier cette donnée par son pointeur.
On comprend tout de suite l'économie de place et le fait qu'une fonction ou une procédure puisse renvoyer plusieurs arguments modifiés alors qu'une fonction ne renvoie qu'une valeur.

Donc il n'est pas rentable de passer par référence une valeur de type "integer" ou "long", tout simplement parce que son pointeur prend plus de place que la donnée elle même.
Cela le devient pour une structure, un tableau ou une chaine de caractères.

Commentaire de jibob le 06/07/2009 19:37:57


Concernant le mot clé "Call" qui au départ est une instruction assembleur x86, qui signifie "Appel" personnellement je le trouve très utile pour 2 raisons:
- il permet de se rapprocher de la représentation visuelle d'une fonction C dont les arguments sont toujours encadrés de parenthèses.
- de relire un programme plus facilement et d'identifier facilement les procédures qui ne peuvent plus se confondre avec du traitement de données.

A noter que "call" n'est pas limité aux fonctions dont on veut ignorer le résultat, mais s'étend aux procédures (sub).

Commentaire de Ecruos le 04/11/2009 02:57:56

Notre prof. pour nous faire comprendre la différence nous avait dis que 'ByVal' ne prend que la valeur de la variable donc la variable ne change pas durant la fonction tandis que 'ByRef' agit sur la variable et son emplacement dans la mémoire donc la variable peut changer pendant le l'appel de la fonction
Mais la j'ai bien compris la différence? Merci à vous ^^

Commentaire de Ecruos le 04/11/2009 03:02:15

concernant le 'Call' que je n'aime pas utilisé d'ailleurs xD a-t il une véritable utilité? autre que son utilité à rendre le code plus clair, je parle du côté performance, optimisation... ?!

Commentaire de bitshifter le 04/11/2009 15:14:14

Pour "Ecruos", 'Call' est un fossile qui a été conservé pour des raisons de compatibilité.
Si 'Call' est utilisé, il empêche le retour de valeur tel myWar = myFunction(Foo).
Dans ce cas, il faut passer Foo 'ByRef.'

Pour 'JiBob', l'avantage de  ByVal est que des 'accidents' n'arrivent pas.

>il n'est pas rentable de passer par référence une valeur de type "integer" ou "long", tout >simplement parce que son pointeur prend plus de place que la donnée elle même.

De plus, le plus petit format 'natif' est de type 'Long'. 'Integer' oblige à faire des trucs pour passer seulement 2 bytes.

>Cela le devient pour une structure, un tableau ou une chaine de caractères.

C'est même la seulte facon de les passer.

Commentaire de phpamateur le 01/12/2009 16:39:46

je tiens à remercier tout d'abord l'éditeur de ce tuto, il est vraiment intéressent et pédagogique. En ce qui concerne le passage par byref ou byval , ou autrement dit par valeur ou par adresse comme dans le langage C (ce qui nous ramène à parler des pointeurs); C'est un choix qui reste à prendre par le programmeur en prenant en considération les points suivant :
- Le taux d'utilisation mémoire (le byref permet une bonne optimisation)
- La réutilisation du code, si le code sera utilisé par d'autres personne vaudrait mieux protéger ses variables lors du passage, le choix du byval est judicieux.
- La nature des données à manipuler , pour des tableau ou des listes chaînées, vaudrait mieux utilisé le byref. Par contre pour des type simple le choix du byval par fois est trés optimum comme dit "bitshifter".
L'essentiel en tout cas c'est la maitrise du concept du byval et byref, le reste c'est salade à faire.

Commentaire de VicoLaChips2 le 02/02/2010 01:02:25

Bien vue la notion de pointeur BIBOP :)

J'ai mis un tas de temps à me retrouver sur la pile, pendant que le ramasse miette se goinfrais de byval...
sale vie pour une variable !

Fin sans ça ... à part les machines à café qui prog en C sans dek ?!

Commentaire de VicoLaChips2 le 02/02/2010 01:06:54

9!

Commentaire de chonburi le 16/05/2011 08:11:57

ByRef est très utile si vous devez modifier deux variables (ou plus) dans une fonction, en gardant à l'esprit qu'une fonction ne peut retourner qu'une seule valeur.
Je ne déclare presque jamais de variable au niveau module et jamais en Public. Un exemple de variable que je vais déclarer au niveau module (feuille) c'est par exemple une connexion ADO ou un recordset. Si je dois conserver une valeur, soit je la stocke dans le Tag d'un contrôle, soit je la passe de procédure en procédure par ByVal ou ByRef selon le cas. ByVal et surtout ByRef, c'est très puissant, cela évite de déclarer des kirielles de variables en début de module.

Commentaire de bitshifter le 17/05/2011 02:42:41

Argh....

Que ceux qui me donnent une note la mette pour qu'elle s'affiche, SVP...  ;-)

Commentaire de nico84240 le 10/01/2012 11:02:16

Ah ben ça alors je me coucherai moins bête ce soir (si c'est possible !)

3 questions :
- si on ne précise rien c'est byval par défaut ?
- dans le cas d'une procédure récursive, est-ce que byref est possible ?
- si j'envoie une constante en face d'une byref keskispas ?

Commentaire de nico84240 le 10/01/2012 11:14:58

Bon en fait j'ai répondu à mes questions :
- byref par défaut
- récursif compatible avec byref (j'en fait sans avoir précisé byval)
- une constante ou une formule est compatible avec byref (à condition de ne pas essayer de modifier la valeur j'imagine)

 Ajouter un commentaire




Nos sponsors


Sondage...

Comparez les prix

CalendriCode

Février 2012
LMMJVSD
  12345
6789101112
13141516171819
20212223242526
272829    

Consulter la suite du CalendriCode

Photothèque

 
Développement réalisé par Nicolas SOREL (Nix) avec l'aide de : Cyril DURAND et Emmanuel (EBArtSoft), Merci à Vincent pour ses précieux conseils.
CodeS-SourceS.com© Toute reproduction même partielle est interdite sauf accord écrit du Webmaster
CodeS-SourceS.com© est une marque déposée tous droits réservés

Google Coop CodeS-SourceS Google Coop CodeS-SourceS
Temps d'éxécution de la page : 0,328 sec (3)

Nous contacter | Annoncer sur CodeS-SourceS | Mentions légales