Novembre 2024 | Lun | Mar | Mer | Jeu | Ven | Sam | Dim |
---|
| | | | 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 | | Calendrier |
|
|
| La valeur de adr(variable) peut changer ? | |
| | Auteur | Message |
---|
Klaus
Nombre de messages : 12331 Age : 75 Localisation : Ile de France Date d'inscription : 29/12/2009
| Sujet: La valeur de adr(variable) peut changer ? Ven 1 Mar 2013 - 17:52 | |
| C'est une question spécifiquement pour Jack:Je rencontre un phénomène bizarre. Je mémorise l'adresse de certaines variables dans un tableau, pour m'en servir le moment venu. Mais lorsque je m'en sers en paramètre à uune DLL, j'obtiens une violation de mémoire. Et, après vérification, je constate que toutes les adresses que j'ai mémorisées au début, ne sont plus d'actualité lorsque j'appelle ma fonction DLL: toutes les adresses des variables ont changé, alors que leurs valeurs restent inchangées, et les variables concernées sont les premières définies dans la liste des variables globales du programme. Après analyse, j'ai trouvé que ceci se passe si j'ai chargé la DLL, et si j'utilise #INCLUDE "KGF_SUB.bas", un gros module qui fait actuellement 1866 lignes de source Panoramic. Question: est-ce normal que les adresses des variables changent ? Et si oui, est-ce qu'on peut l'éviter ou est-ce qu'il faut systématiquement reprendre les adresses immédiatement avant ou même dans l'appel d'une fonction DLL ? EDIT J'ai trouvé une astuce pour pallier à ce problème. Le mémorise base%=adr(number_click) dans une variable, au moment où je mémorise toutes mes adresses. Puis, juste avant l'appel de ma fonction DLL, je calcule delta%=adr(number_click)-base% et je passe delta% à la fonction DLL. De façon interne, j'additionne systématiquement delta% à toutes les adresses, et ça marche ! Mais j'aimerais vraiment savoir si ce problème de changement d'adresse vient d'une anomalie de programmation de ma part, ou si c'est inhérent à l'implémentation de l'interpréteur. EDIT à toutes fins utiles: KGF.dll et KGF_SUB.bas se trouvent sur mon site de stockage MyDrive: URL: MyDriveusername : panoramic@klausgunther password : panoramic123 Dossier DLLs pour KGF.dll Dossier DLLs\KGF_SUB pour KGF_SUB.bas
Dernière édition par Klaus le Sam 9 Mar 2013 - 12:24, édité 1 fois | |
| | | Jack Admin
Nombre de messages : 2395 Date d'inscription : 28/05/2007
| Sujet: Re: La valeur de adr(variable) peut changer ? Sam 9 Mar 2013 - 8:11 | |
| La directive #INCLUDE ne change pas l'adresse des variables, car elle est effectuée par l'éditeur, qui insère les lignes AVANT d'appeler Panoramic pour l'exécution. FREE V change les adresses des variables qui ont été déclarées après la déclaration de V: - Code:
-
dim V dim VV free V rem l'adresse de VV est changée De même, à la fin de l'exécution d'un sous-programme, END_SUB détruit les variables locales créées avec DIM_LOCAL. Une variable globale créée avec DIM dans un sous-programme aura son adresse modifiée après le END_SUB. | |
| | | Klaus
Nombre de messages : 12331 Age : 75 Localisation : Ile de France Date d'inscription : 29/12/2009
| Sujet: Re: La valeur de adr(variable) peut changer ? Sam 9 Mar 2013 - 8:54 | |
| - Citation :
- Et, après vérification, je constate que toutes les adresses que j'ai mémorisées au début, ne sont plus d'actualité lorsque j'appelle ma fonction DLL: toutes les adresses des variables ont changé, alors que leurs valeurs restent inchangées, et les variables concernées sont les premières définies dans la liste des variables globales du programme.
Je déclare bien les variables en question comme variables globales, et le les déclare comme les toutes ptrmières variables du programme. Si je n'utilisa pas #INCLUDE pour inclure KGF_SUB.bas, mais je mets deux ou 3 procédures directement dans le source par copîer/coller, et si je ne charge pas KGF.dll, les adresses des variables restent inchangées. Mais si j'inclus KGF_SUB.bas par #INCLUDE, si si je charge KGF.dll, alors mes adresses, déterminées à un instant t, ne sont plus garanties être les mêmes à un instant t'. Et c'est toute la table de symboles de Panoramic qui est relocalisée, car l'adresse des variables système telles que NUMBER_CLICK ont changé également ! C'est d'ailleurs ce qui me permet de ccntourner le problème en mémorisant systématiquement l'adresse de NUMBER_CLICK en même temps que les adresses de mes variables. Et lorsque je veux utiliser les adresses, je reprends à nouveau l'adresse de NUMBER_CLICK, j'établis la différence avec son adresse initiale et j'additionne cette valeur à toutes mes adresses mémorisées au moment de l'utilisation. Et je tombe systématiquement juste. se delta comme je l'appelle, n'est pas le même suivant le moment de sa détermination dans le programme. Cela signifie que la table de symboles de Panoramic est dynamiquement déplacée dans l'espace mémoire virtuel du programme. C'est étonnant. J'ai fait des centaines d'essais, et ce comportement se confirme à des moments aléatoires, mais uniquement si le programme est relativement gros. | |
| | | Klaus
Nombre de messages : 12331 Age : 75 Localisation : Ile de France Date d'inscription : 29/12/2009
| Sujet: Re: La valeur de adr(variable) peut changer ? Sam 9 Mar 2013 - 10:52 | |
| @Jack: Pour mettre lr problème en évidence, je te poste ici deux programmes. Le premier crée un fichier dit binaire avec 12 enregistrements de 72 caractères, formatés chacun en 3 zones: un entier (3 octets), un flottant (8 octets) et une chaîne de caractères de longueur fixe (60 caractères). Il faut exécuter ce programme une fois pour créer ce fichier, puis on peut le quitter: - Code:
-
' demo_fichiers_binaires_zones_fixes.bas
' Ce programme crée un fichier binaire contenant ' 12 "enregistrements" ayant chacun 3 zones: ' 1 entier contenant le numéro d'enregistrement ' 1 flottant contenant le numéro d'enregistrement * 3 + 0.17 ' 1 chaîne de caractères contenant str$(zone flottante) ' Afin de produire des enregsitrements de longueur fixe, ' la 3ème zone est fixée à 60 caractères. Chaque enregsitrement ' a donc 4 + 8 + 60 = 72 caractères. ' ' Le programme propose une zone pour saisir un numéro d'enregistrement ' entre 1 et 12, un bouton "Lire" et un mémo montrant les données lues.
label lire, sortie
dim i%, v, s$, buf$, n%, p%, num% dim nom$ : nom$ = "test_fichier_binaire.dat"
on_close 0,sortie
alpha 1 : top 1,20 : left 1,20 : caption 1,"Enregistrement (1...12):" edit 11 : top 11,20 : left 11,150 : width 11,40 : text 11,"0" button 12 : top 12,50 : left 12,150 : caption 12,"Lire" : on_click 12,lire memo 13 : top 13,80 : left 13,150 : width 13,300 : height 13,300
KGF_initialize("KGF.dll")
OpenBinaryFile(nom$)
' on crée d'abord un fichier "vide" de 12*72 caractères, ' soit 864 caractères buf$ = string$(12*72," ") WriteStringToBinaryFile(nom$,buf$)
' boucle pour la création des 12 enregistrements for i%=1 to 12 ' la variable i% est la zone 1 ' on construit la zone 2 v = i%*3 + 0.17 ' et la zone 3 s$ = left$(str$(v)+string$(60," "),60) ' on écrit l'enregistrement à sa place p% = (i%-1)*72 + 1 : ' calculer la position de début ' d'abord, écrire la zone 1: ReplaceBlockInBinaryFileByInteger(nom$,i%,p%,0) ' puis, écrire la zone 2: ReplaceBlockInBinaryFileByFloat(nom$,v,p%+4,0) ' enfin, écrire la zone 3: ReplaceBlockInBinaryFile(nom$,adr(s$),60,p%+12,1) next i%
end
lire: if numeric(text$(11))=0 message "Invalide." return end_if num% = val(text$(11)) if num%<1 or num%>12 message "Invalide." return end_if p% = (num%-1)*72 + 1 : ' calculer la position de début clear 13 item_add 13,"Enregistrement "+str$(num%) ' d'abord lire la zone 1 i% = 0 ReadBlockFromBinaryFileToInteger(nom$,p%) item_add 13,"Zone 1: "+str$(ReadBlockFromBinaryFileToInteger%) ' puis, lire la zone 2: ReadBlockFromBinaryFileToFloat(nom$,p%+4) item_add 13,"zone 2: "+str$(ReadBlockFromBinaryFileToFloat) ' enfin, lire la zone 3: ReadBlockFromBinaryFileToString(nom$,60,p%+12) item_add 13,"Zone 3: ["+ReadBlockFromBinaryFileToString$+"]" return
sortie: CloseBinaryFile(nom$) return
#INCLUDE "KGF_SUB.bas"
Le second programme peut lire, puis modifier, un des 12 enregistrements écrits dans la phase précédente. J'y ai ajouté des messages indiquant la valeur de adr(number_click) à des moments stratégiques, et on constate aisément que cette valeur a changé entre le moment où l'on mémorise les adresses (lignes 15, 16 et 17) et le moment où l'on veut utiliser ces adresses (lignes 33 et 43): - Code:
-
' test_definition_record.bas
label lire, modifier
dim nfld%, fld1%, fld2, fld3$ dim res%, base%, nrec%, lu% dim nom$ : nom$ = "test_fichier_binaire.dat" fld3$ = string$(60," ")
KGF_initialize("KGF.dll")
define_record(3) message "1: adr(nuber_click)="+str$(adr(number_click))
add_integer_field(adr(fld1%)) add_float_field(adr(fld2)) add_string_field(adr(fld3$),60)
build_record()
alpha 10 : top 10,10 : left 10,10 : caption 10,"Enregistrement:" edit 11 : top 11,10 : left 11,100 : width 11,40 : text 11,"0" button 12 : top 12,10 : left 12,160 : caption 12,"Lire" on_click 12,lire button 13 : top 13,10 : left 13,320 : caption 13,"Modifier" on_click 13,modifier
end
lire: nrec% = val(text$(11)) message "2: adr(nuber_click)="+str$(adr(number_click)) ReadBinaryFileRecord(nom$,record$,nrec%) message "lu: fld1%="+str$(fld1%)+" fld2="+str$(fld2)+" fld3$="+fld3$ lu% = 1 return modifier: if lu%=0 then return fld2 = 0 - fld2 fld3$ = left$(trim$(fld3$)+" bis"+string$(60," "),60) message "3: adr(nuber_click)="+str$(adr(number_click)) WriteBinaryFileRecord(nom$,record$,nrec%) message "écrit: fld1%="+str$(fld1%)+" fld2="+str$(fld2)+" fld3$="+fld3$ return
#INCLUDE "KGF_SUB.bas"
Mais j'ai vérifié: ce décalage est le même pour toutes les adresses des premières variables définies (variables globales définies en début de programme, sans utilisation de FREE pour une d'entre elles). C'est pourquoi l'addition du delta calculé par la différence entre les adresses de NUMBER_CLICK aux moments stratégiques aux adresses des variables mémorisées produit l'adresse correcte au moment critique. Tu crois qu'il y aurait un moyen de donner l'accès aux données d'une façon plus universelle ? Indépendante de la situation dynamique du programme ? D'autant plus que adr(chaîne$) ne donne pas l'adresse du premier caractère des données comme adr(entier%) ou adr(flottant), mais l'adresse d'un emplacement 32 bits contenant l'adresse du premier caractère des données. En effet, dans la DLL, il faut faire: - Code:
-
function MaFonction(chaine: pstring):integer; stdcall; export; var s: string; begin s := chaine^; ... pour avoir la chaîne de caractères. Ceci ne marche pas: - Code:
-
function MaFonction(chaine: pbyte):integer; stdcall; export; var c: byte; begin c := chaine^; ... pour prendre le premier caractère de la chaîne. Bon, ce n'est pas grave, il suffit de le savoir. Mais effectivement, adr(variable) ne donne pas systématiquement l'adresse du premier caractère des données. | |
| | | Contenu sponsorisé
| Sujet: Re: La valeur de adr(variable) peut changer ? | |
| |
| | | | La valeur de adr(variable) peut changer ? | |
|
Sujets similaires | |
|
| Permission de ce forum: | Vous ne pouvez pas répondre aux sujets dans ce forum
| |
| |
| |