|
| Performancespørgsmål Fra : Jonas Jørgensen |
Dato : 28-09-01 17:33 |
|
Er der nogen der ved om der er nogen performancemæssig forskel på de to
følgende syntakser? Bare en tanke...
*** SYNTAKS 1: ***
Private Sub EtEllerAndet()
If x = y Then
gør_noget
Else
gør_noget_andet
End If
End Sub
*** SYNTAKS 2: ***
Private Sub EtEllerAndet()
If x = y Then
gør_noget
Exit Sub
End If
gør_noget_andet
End Sub
| |
Mikkel Bundgaard (28-09-2001)
| Kommentar Fra : Mikkel Bundgaard |
Dato : 28-09-01 20:08 |
|
Jonas Jørgensen <jonasj@jonasj.dk> wrote in message
news:3BB4A622.29BAD235@jonasj.dk...
> Er der nogen der ved om der er nogen performancemæssig forskel på de to
> følgende syntakser? Bare en tanke...
>
> *** SYNTAKS 1: ***
>
> Private Sub EtEllerAndet()
> If x = y Then
> gør_noget
> Else
> gør_noget_andet
> End If
> End Sub
>
> *** SYNTAKS 2: ***
>
> Private Sub EtEllerAndet()
> If x = y Then
> gør_noget
> Exit Sub
> End If
>
> gør_noget_andet
> End Sub
Hej Jonas
Jeg har prøvet at køre en lille test og denne tyder på at der ikke er den
store forskel på de to metoder. Jeg har kaldt hver af de to procedure
10.000.000 gange og som det kan ses på resultaterne nedenunder ligger de
meget ens.
Resultater:
Test If Else 22,7890625
Test If Else 23,40625
Test If Exit 22,84375
Test If Exit 22,6015625
Håber du kan bruge det til noget .
--
Mikkel Bundgaard
IT University of Copenhagen
http://officehelp.gone.dk
Se SpaceCommunicator - en peer-to-peer chat-applikation i Java
| |
Jonas Jørgensen (29-09-2001)
| Kommentar Fra : Jonas Jørgensen |
Dato : 29-09-01 16:43 |
|
Mikkel Bundgaard wrote:
>
> Jonas Jørgensen <jonasj@jonasj.dk> wrote in message
> news:3BB4A622.29BAD235@jonasj.dk...
> > Er der nogen der ved om der er nogen performancemæssig forskel på de to
> > følgende syntakser? Bare en tanke...
[snip]
> Hej Jonas
>
> Jeg har prøvet at køre en lille test og denne tyder på at der ikke er den
> store forskel på de to metoder. Jeg har kaldt hver af de to procedure
> 10.000.000 gange og som det kan ses på resultaterne nedenunder ligger de
> meget ens.
>
> Resultater:
> Test If Else 22,7890625
> Test If Else 23,40625
> Test If Exit 22,84375
> Test If Exit 22,6015625
>
> Håber du kan bruge det til noget .
Jeg skulle egentlig ikke bruge det til noget seriøst, det var bare en
tanke der pludselig dukkede op i mit hoved. Men tak alligevel!
/Jonas
| |
Tomas Christiansen (29-09-2001)
| Kommentar Fra : Tomas Christiansen |
Dato : 29-09-01 22:51 |
|
Jonas Jørgensen skrev:
> Jeg skulle egentlig ikke bruge det til noget seriøst, det var bare
en
> tanke der pludselig dukkede op i mit hoved. Men tak alligevel!
Her er der et andet lille tankeeksperiment.
Hvad er hurtigst at overføre og at bruge: Variabler overført til en
procedure ByVal eller ByRef?
-------
Tomas
| |
Jonas Jørgensen (29-09-2001)
| Kommentar Fra : Jonas Jørgensen |
Dato : 29-09-01 23:07 |
|
Tomas Christiansen wrote:
> Her er der et andet lille tankeeksperiment.
>
> Hvad er hurtigst at overføre og at bruge: Variabler overført til en
> procedure ByVal eller ByRef?
Jeg vil skyde på at det er ByRef, i hvert fald hvis vi snakker variabler
med meget data i. Hvis man f.eks. har en streng som indeholder 10
kilobyte data, skal de 10 kilobyte kopieres til et andet sted i
hukommelsen hvis man bruges ByVal. Med ByRef skal der blot gemmes en
henvisning til de eksisterende 10 kilobyte.
| |
Tomas Christiansen (30-09-2001)
| Kommentar Fra : Tomas Christiansen |
Dato : 30-09-01 22:05 |
|
Jonas Jørgensen skrev:
> Jeg vil skyde på at det er ByRef, i hvert fald hvis vi snakker
variabler
> med meget data i.
Jo... Men hvilke variabler indeholder (kan indeholde) meget data?
Kun strenge, ikke sandt? Alle andre simple datatyper er forholdsvis
korte.
Hvad er så hurtigst: At overføre og bruge en reference (som fylder 32
bit) til en variabel (som måske også fylder 32 bit), som jo i sig selv
kan være reference til et sted i lageret, hvor data ligger, eller blot
at overføre de (i dette tilfælde) 32 bit med værdien?
Med strenge stiller sagen sig naturligvis anderledes.
Desuden kan, naturligvis, tabeller og user-defined-types indeholde
meget store mængder data, og de kan være tunge at overføre.
Men hvad med sådan noget som objekter?
De kan indeholde meget store mængder data, men de bliver jo aldrig
overført (problemet med at "klone" et objekt) - det er altid kun
referencen til objektet, som overføres. En ByRef overførsel af et
objekt, vil overføre en reference til det sted i lageret hvor
referencen til objektet er, hvorimod ByVal overfører objektets
reference. Overførsel: ingen forskel. Brug: ekstra overhead ved ByRef
overførsel.
Bemærk venligst at jeg IKKE har performancetestet nogen af mine
overvejelser (og kommer nok aldrig til at gøre det), men jeg kom blot
til at tænke på det i forbindelse med dit spørgsmål.
-------
Tomas
| |
Jonas Jørgensen (30-09-2001)
| Kommentar Fra : Jonas Jørgensen |
Dato : 30-09-01 22:44 |
|
Tomas Christiansen wrote:
>
> Jonas Jørgensen skrev:
> > Jeg vil skyde på at det er ByRef, i hvert fald hvis vi snakker
> variabler
> > med meget data i.
>
> Jo... Men hvilke variabler indeholder (kan indeholde) meget data?
> Kun strenge, ikke sandt? Alle andre simple datatyper er forholdsvis
> korte.
>
> Hvad er så hurtigst: At overføre og bruge en reference (som fylder 32
> bit) til en variabel (som måske også fylder 32 bit), som jo i sig selv
> kan være reference til et sted i lageret, hvor data ligger, eller blot
> at overføre de (i dette tilfælde) 32 bit med værdien?
Hmm... godt spørgsmål...
| |
Frank Bertelsen (22-01-2002)
| Kommentar Fra : Frank Bertelsen |
Dato : 22-01-02 16:57 |
|
> Tomas Christiansen wrote:
>
> Hvis man f.eks. har en streng som indeholder 10
> kilobyte data, skal de 10 kilobyte kopieres til et andet sted i
> hukommelsen hvis man bruges ByVal.
Det er nu ikke helt korrekt.
Det som bliver kopieret, når man overfører en streng ByVal, er pointeren
til det sted, hvor data ligger.
Med ByRef overfører man adressen på denne pointer.
I begge tilfælde overføres kun 4 bytes.
--
Posted via Mailgate.ORG Server - http://www.Mailgate.ORG
| |
Tomas Christiansen (22-01-2002)
| Kommentar Fra : Tomas Christiansen |
Dato : 22-01-02 23:51 |
|
Frank Bertelsen skrev:
> > Tomas Christiansen wrote:
> >
> > Hvis man f.eks. har en streng som indeholder 10
> > kilobyte data, skal de 10 kilobyte kopieres til et andet sted i
> > hukommelsen hvis man bruges ByVal.
>
> Det er nu ikke helt korrekt.
>
> Det som bliver kopieret, når man overfører en streng ByVal, er
pointeren
> til det sted, hvor data ligger.
>
> Med ByRef overfører man adressen på denne pointer.
>
> I begge tilfælde overføres kun 4 bytes.
Det er nu helt korrekt, hvilket du vil opdage hvis du prøver at ændre
i strengen overført ByVal kontra overført ByRef.
Så vil du opdage forskellen - og det er jo hele idéen med ByVal/ByRef!
-------
Tomas
| |
Frank Bertelsen (25-01-2002)
| Kommentar Fra : Frank Bertelsen |
Dato : 25-01-02 15:40 |
|
Jeg er udmærket godt klar over, at en streng overført ByRef kan
modificeres i den kaldte rutine, det kan den ikke hvis den er overført
ByVal, men det betyder ikke at data nødvendigvis bliver kopieret.
Når den kaldte rutine modificerer strengen (overført ByVal), så
oprettes der et nyt data-areal et eller andet sted i hukommelsen, og
pointeren bliver opdateret, så den peger på dette data-areal. Men da
det er pointeren, som er blevet overført ByVal, så ændrer dette ikke
på den oprindelige pointer i det kaldende program, den peger stadig
på det gamle data-areal. Der er altså 2 data-arealer og 2 pointere.
Et eksempel forklarer det nok bedre:
Dim Tekst As String
Tekst = "abc"
ModifyText Tekst
Print Tekst
Sub ModifyText(ByVal Tekst As String)
Tekst = "123"
End Sub
Når dette program køres, printer det "abc", som forventet.
Nu sætter vi nogle tal på:
Vi antager at sætningen 'Dim Tekst As String' allokerer 4 bytes i
hukommelsen på adresse 100.
Sætningen 'Tekst = "abc"' allokerer et data-areal på adresse 200, som
indeholder teksten "abc" (en nul-termineret unicode-streng). De 4 bytes
på adresse 100 får derefter indholdet 200 (pointer til data-arealet).
Når rutinen ModifyText kaldes, så overføres tallet 200 på stacken.
Underutinen har da adgang til data via denne pointer.
Når nu sætningen 'Tekst = "123"' udføres, så oprettes et nyt data-areal
på adresse 300 med indholdet "123" (igen en nul-termineret
unicode-streng), og pointeren PÅ STACKEN ændres til 300.
Når rutinen derefter returnerer, frigives data på adresse 300, og
tallet 300 fjernes fra stacken. Tilbage i hovedprogrammet, indeholder
adresse 100 stadig tallet 200, og adresse 200 indeholder stadig den
oprindelige tekst "abc".
Havde vi i stedet overført ByRef, så ville tallet 100 være blevet lagt
på stacken. Efter allokering af det nye data-areal på adresse 300, ville
adresse 100 få indholdet 300, og data på adresse 200 ville blive
frigivet (da der nu ikke er nogle referencer til dette areal).
Data på adresse 300 vil derimod ikke blive frigivet, da det jo er
refereret via adresse 100.
Når man modificerer en streng, ændrer man altså ikke i de eksisterende
data. Man opretter en ny streng, og modificerer pointeren.
Med API-kald er det lidt anderledes. API-funktioner arbejder på
ANSI-strenge (1 byte pr. tegn), mens VB arbejder på Unicode-strenge
(2 bytes pr. tegn). Her foretager VB en intern konvertering mellem de
to formater før og efter kaldet, så her bliver data altid kopieret
(også ved overførsel ByRef). Det er stadigvæk kun pointere, der
overføres, men nu er det bare en temporær ANSI-kopi der arbejdes på,
og det er den, som kan modificeres, hvis man overfører ByRef.
En komplet beskrivelse af stenge i VB kan ses på følgende side:
http://www.oreilly.com/catalog/win32api/chapter/ch06.html
--
Posted via Mailgate.ORG Server - http://www.Mailgate.ORG
| |
Carsten Suurland (25-01-2002)
| Kommentar Fra : Carsten Suurland |
Dato : 25-01-02 17:06 |
|
Hej Frank
Det er ikke helt rigtigt at pointeren først opdateres i det øjeblik den
kaldte rutine ændrer på tekststrengen. Ej heller at der først oprettes et
nyt dataområde på dette tidspunkt.
Du kan teste det ved hjælp af nedestående:
********************************
Private Sub Form_Load()
Dim s As String
Dim cnt As Long
s = String(10000, "x")
For cnt = 1 To 10
Debug.Print "Out " & VarPtr(s)
TransferText s
Next
End Sub
Private Sub TransferText(ByVal x As String)
Debug.Print "In " & VarPtr(x)
End Sub
********************************
Den kaldte rutine (TransferText) ændrer IKKE på de modtagne data, den
aflæser kun pointeren, men som du vil se, så er der overført en anden
pointer alligevel... Og da VB sikkert ikke overfører en ugyldig pointer, må
det jo betyde, at der også er data det sted hvor der henvises til; altså er
der lavet en kopi af tekststrengen inden rutinen kaldes.
Hver gang der overføres data ByVal så tages der først en kopi af data til et
nyt område, hvorefter pointeren til dette område overføres.
/Carsten Suurland
| |
Frank Bertelsen (25-01-2002)
| Kommentar Fra : Frank Bertelsen |
Dato : 25-01-02 18:26 |
|
Hej Carsten,
Funktionen VarPtr() giver dig adressen på POINTEREN til dataarealet,
ikke adressen på selve dataarealet. De to værdier er forskellige, fordi
pointerne ligger forskellige steder:
> Private Sub Form_Load()
> Dim s As String
> Dim cnt As Long
>
> s = String(10000, "x")
> For cnt = 1 To 10
> Debug.Print "Out " & VarPtr(s)
> TransferText s
> Next
> End Sub
>
> Private Sub TransferText(ByVal x As String)
> Debug.Print "In " & VarPtr(x)
> End Sub
VarPtr(s) giver adressen på 'Dim s As String' i Form_Load().
VarPtr(x) giver en adresse på stacken.
Men disse to adresser indeholder begge det samme tal, nemlig en pointer
til dataarealet.
PS: Jeg beklager mine mange fejlposteringer. Der er gået et eller andet
helt galt for mig. Sorry.
--
Posted via Mailgate.ORG Server - http://www.Mailgate.ORG
| |
Carsten Suurland (23-01-2002)
| Kommentar Fra : Carsten Suurland |
Dato : 23-01-02 09:20 |
|
Hej Frank
Overførsel ByVal tager altid en kopi af de pågældende data.
Ikke af pointeren...
Den eneste undtagelse er i forbindelse med API-kald, hvor ByVal vil overføre
en pointer til de pågældende data.
/Carsten Suurland
| |
Frank Bertelsen (25-01-2002)
| Kommentar Fra : Frank Bertelsen |
Dato : 25-01-02 14:11 |
|
> Overførsel ByVal tager altid en kopi af de pågældende data.
> Ikke af pointeren...
Nej, overførsel af strenge i VB foregår altid via pointere.
Der kopieres ingen data.
> Den eneste undtagelse er i forbindelse med API-kald, hvor ByVal vil overføre
> en pointer til de pågældende data.
Nej, ved API-kald bliver der netop taget en kopi af data, da VB altid
arbejder med strenge i Unicode, mens API-funktioner arbejder med
strenge i ANSI.
Jeg lyder måske meget skråsikker, men jeg har arbejdet meget med
overførsel af strenge mellem forskellige programmeringssprog, og
konvertering mellem Unicode og ANSI, så jeg ved hvordan det foregår.
Jeg er udmærket godt klar over, at en streng overført ByRef kan
modificeres i den kaldte rutine, det kan den ikke hvis den er overført
ByVal, men det betyder ikke at data nødvendigvis bliver kopieret.
Når den kaldte rutine modificerer strengen (overført ByVal), så
oprettes der et nyt data-areal et eller andet sted i hukommelsen, og
pointeren bliver opdateret, så den peger på dette data-areal. Men da
det er pointeren, som er blevet overført ByVal, så ændrer dette ikke
på den oprindelige pointer i det kaldende program, den peger stadig
på det gamle data-areal. Der er altså 2 data-arealer og 2 pointere.
Et eksempel forklarer det nok bedre:
Dim Tekst As String
Tekst = "abc"
ModifyText Tekst
Print Tekst
Sub ModifyText(ByVal Tekst As String)
Tekst = "123"
End Sub
Når dette program køres, printer det "abc", som forventet.
Nu sætter vi nogle tal på:
Vi antager at sætningen 'Dim Tekst As String' allokerer 4 bytes i
hukommelsen på adresse 100.
Sætningen 'Tekst = "abc"' allokerer et data-areal på adresse 200, som
indeholder teksten "abc" (en nul-termineret unicode-streng). De 4 bytes
på adresse 100 får derefter indholdet 200 (pointer til data-arealet).
Når rutinen ModifyText kaldes, så overføres tallet 200 på stacken.
Underutinen har da adgang til data via denne pointer.
Når nu sætningen 'Tekst = "123"' udføres, så oprettes et nyt data-areal
på adresse 300 med indholdet "123" (igen en nul-termineret
unicode-streng), og pointeren PÅ STACKEN ændres til 300.
Når rutinen derefter returnerer, frigives data på adresse 300, og
tallet 300 fjernes fra stacken. Tilbage i hovedprogrammet, indeholder
adresse 100 stadig tallet 200, og adresse 200 indeholder stadig den
oprindelige tekst "abc".
Havde vi i stedet overført ByRef, så ville tallet 100 være blevet lagt
på stacken. Efter allokering af det nye data-areal på adresse 300, ville
adresse 100 få indholdet 300, og data på adresse 200 ville blive
frigivet (da der nu ikke er nogle referencer til dette areal).
Data på adresse 300 vil derimod ikke blive frigivet, da det jo er
refereret via adresse 100.
Når man modificerer en streng, ændrer man altså ikke i de eksisterende
data. Man opretter en ny streng, og modificerer pointeren.
Med API-kald er det lidt anderledes. API-funktioner arbejder på
ANSI-strenge (1 byte pr. tegn), mens VB arbejder på Unicode-strenge
(2 bytes pr. tegn). Her foretager VB en intern konvertering mellem de
to formater før og efter kaldet, så her bliver data altid kopieret
(også ved overførsel ByRef). Det er stadigvæk kun pointere, der
overføres, men nu er det bare en temporær ANSI-kopi der arbejdes på,
og det er den, som kan modificeres, hvis man overfører ByRef.
En komplet beskrivelse af stenge i VB kan ses på følgende side:
http://www.oreilly.com/catalog/win32api/chapter/ch06.html
--
Posted via Mailgate.ORG Server - http://www.Mailgate.ORG
| |
Frank Bertelsen (25-01-2002)
| Kommentar Fra : Frank Bertelsen |
Dato : 25-01-02 14:20 |
|
> Overførsel ByVal tager altid en kopi af de pågældende data.
> Ikke af pointeren...
Nej, overførsel af strenge i VB foregår altid via pointere.
Der kopieres ingen data.
> Den eneste undtagelse er i forbindelse med API-kald, hvor ByVal vil overføre
> en pointer til de pågældende data.
Nej, ved API-kald bliver der netop taget en kopi af data, da VB altid
arbejder med strenge i Unicode, mens API-funktioner arbejder med
strenge i ANSI.
Jeg lyder måske meget skråsikker, men jeg har arbejdet meget med
overførsel af strenge mellem forskellige programmeringssprog, og
konvertering mellem Unicode og ANSI, så jeg ved hvordan det foregår.
Jeg er udmærket godt klar over, at en streng overført ByRef kan
modificeres i den kaldte rutine, det kan den ikke hvis den er overført
ByVal, men det betyder ikke at data nødvendigvis bliver kopieret.
Når den kaldte rutine modificerer strengen (overført ByVal), så
oprettes der et nyt data-areal et eller andet sted i hukommelsen, og
pointeren bliver opdateret, så den peger på dette data-areal. Men da
det er pointeren, som er blevet overført ByVal, så ændrer dette ikke
på den oprindelige pointer i det kaldende program, den peger stadig
på det gamle data-areal. Der er altså 2 data-arealer og 2 pointere.
Et eksempel forklarer det nok bedre:
Dim Tekst As String
Tekst = "abc"
ModifyText Tekst
Print Tekst
Sub ModifyText(ByVal Tekst As String)
Tekst = "123"
End Sub
Når dette program køres, printer det "abc", som forventet.
Nu sætter vi nogle tal på:
Vi antager at sætningen 'Dim Tekst As String' allokerer 4 bytes i
hukommelsen på adresse 100.
Sætningen 'Tekst = "abc"' allokerer et data-areal på adresse 200, som
indeholder teksten "abc" (en nul-termineret unicode-streng). De 4 bytes
på adresse 100 får derefter indholdet 200 (pointer til data-arealet).
Når rutinen ModifyText kaldes, så overføres tallet 200 på stacken.
Underutinen har da adgang til data via denne pointer.
Når nu sætningen 'Tekst = "123"' udføres, så oprettes et nyt data-areal
på adresse 300 med indholdet "123" (igen en nul-termineret
unicode-streng), og pointeren PÅ STACKEN ændres til 300.
Når rutinen derefter returnerer, frigives data på adresse 300, og
tallet 300 fjernes fra stacken. Tilbage i hovedprogrammet, indeholder
adresse 100 stadig tallet 200, og adresse 200 indeholder stadig den
oprindelige tekst "abc".
Havde vi i stedet overført ByRef, så ville tallet 100 være blevet lagt
på stacken. Efter allokering af det nye data-areal på adresse 300, ville
adresse 100 få indholdet 300, og data på adresse 200 ville blive
frigivet (da der nu ikke er nogle referencer til dette areal).
Data på adresse 300 vil derimod ikke blive frigivet, da det jo er
refereret via adresse 100.
Når man modificerer en streng, ændrer man altså ikke i de eksisterende
data. Man opretter en ny streng, og modificerer pointeren.
Med API-kald er det lidt anderledes. API-funktioner arbejder på
ANSI-strenge (1 byte pr. tegn), mens VB arbejder på Unicode-strenge
(2 bytes pr. tegn). Her foretager VB en intern konvertering mellem de
to formater før og efter kaldet, så her bliver data altid kopieret
(også ved overførsel ByRef). Det er stadigvæk kun pointere, der
overføres, men nu er det bare en temporær ANSI-kopi der arbejdes på,
og det er den, som kan modificeres, hvis man overfører ByRef.
En komplet beskrivelse af stenge i VB kan ses på følgende side:
http://www.oreilly.com/catalog/win32api/chapter/ch06.html
--
Posted via Mailgate.ORG Server - http://www.Mailgate.ORG
| |
Frank Bertelsen (25-01-2002)
| Kommentar Fra : Frank Bertelsen |
Dato : 25-01-02 14:49 |
|
> Overførsel ByVal tager altid en kopi af de pågældende data.
> Ikke af pointeren...
Nej, overførsel af strenge i VB foregår altid via pointere.
Der kopieres ingen data.
> Den eneste undtagelse er i forbindelse med API-kald, hvor ByVal vil overføre
> en pointer til de pågældende data.
Nej, ved API-kald bliver der netop taget en kopi af data, da VB altid
arbejder med strenge i Unicode, mens API-funktioner arbejder med
strenge i ANSI.
Jeg lyder måske meget skråsikker, men jeg har arbejdet meget med
overførsel af strenge mellem forskellige programmeringssprog, og
konvertering mellem Unicode og ANSI, så jeg ved hvordan det foregår.
Jeg er udmærket godt klar over, at en streng overført ByRef kan
modificeres i den kaldte rutine, det kan den ikke hvis den er overført
ByVal, men det betyder ikke at data nødvendigvis bliver kopieret.
Når den kaldte rutine modificerer strengen (overført ByVal), så
oprettes der et nyt data-areal et eller andet sted i hukommelsen, og
pointeren bliver opdateret, så den peger på dette data-areal. Men da
det er pointeren, som er blevet overført ByVal, så ændrer dette ikke
på den oprindelige pointer i det kaldende program, den peger stadig
på det gamle data-areal. Der er altså 2 data-arealer og 2 pointere.
Et eksempel forklarer det nok bedre:
Dim Tekst As String
Tekst = "abc"
ModifyText Tekst
Print Tekst
Sub ModifyText(ByVal Tekst As String)
Tekst = "123"
End Sub
Når dette program køres, printer det "abc", som forventet.
Nu sætter vi nogle tal på:
Vi antager at sætningen 'Dim Tekst As String' allokerer 4 bytes i
hukommelsen på adresse 100.
Sætningen 'Tekst = "abc"' allokerer et data-areal på adresse 200, som
indeholder teksten "abc" (en nul-termineret unicode-streng). De 4 bytes
på adresse 100 får derefter indholdet 200 (pointer til data-arealet).
Når rutinen ModifyText kaldes, så overføres tallet 200 på stacken.
Underutinen har da adgang til data via denne pointer.
Når nu sætningen 'Tekst = "123"' udføres, så oprettes et nyt data-areal
på adresse 300 med indholdet "123" (igen en nul-termineret
unicode-streng), og pointeren PÅ STACKEN ændres til 300.
Når rutinen derefter returnerer, frigives data på adresse 300, og
tallet 300 fjernes fra stacken. Tilbage i hovedprogrammet, indeholder
adresse 100 stadig tallet 200, og adresse 200 indeholder stadig den
oprindelige tekst "abc".
Havde vi i stedet overført ByRef, så ville tallet 100 være blevet lagt
på stacken. Efter allokering af det nye data-areal på adresse 300, ville
adresse 100 få indholdet 300, og data på adresse 200 ville blive
frigivet (da der nu ikke er nogle referencer til dette areal).
Data på adresse 300 vil derimod ikke blive frigivet, da det jo er
refereret via adresse 100.
Når man modificerer en streng, ændrer man altså ikke i de eksisterende
data. Man opretter en ny streng, og modificerer pointeren.
Med API-kald er det lidt anderledes. API-funktioner arbejder på
ANSI-strenge (1 byte pr. tegn), mens VB arbejder på Unicode-strenge
(2 bytes pr. tegn). Her foretager VB en intern konvertering mellem de
to formater før og efter kaldet, så her bliver data altid kopieret
(også ved overførsel ByRef). Det er stadigvæk kun pointere, der
overføres, men nu er det bare en temporær ANSI-kopi der arbejdes på,
og det er den, som kan modificeres, hvis man overfører ByRef.
En komplet beskrivelse af stenge i VB kan ses på følgende side:
http://www.oreilly.com/catalog/win32api/chapter/ch06.html
--
Posted via Mailgate.ORG Server - http://www.Mailgate.ORG
| |
Frank Bertelsen (25-01-2002)
| Kommentar Fra : Frank Bertelsen |
Dato : 25-01-02 15:02 |
|
> Overførsel ByVal tager altid en kopi af de pågældende data.
> Ikke af pointeren...
Nej, overførsel af strenge i VB foregår altid via pointere.
Der kopieres ingen data.
> Den eneste undtagelse er i forbindelse med API-kald, hvor ByVal vil overføre
> en pointer til de pågældende data.
Nej, ved API-kald bliver der netop taget en kopi af data, da VB altid
arbejder med strenge i Unicode, mens API-funktioner arbejder med
strenge i ANSI.
Jeg lyder måske meget skråsikker, men jeg har arbejdet meget med
overførsel af strenge mellem forskellige programmeringssprog, og
konvertering mellem Unicode og ANSI, så jeg ved hvordan det foregår.
Jeg er udmærket godt klar over, at en streng overført ByRef kan
modificeres i den kaldte rutine, det kan den ikke hvis den er overført
ByVal, men det betyder ikke at data nødvendigvis bliver kopieret.
Når den kaldte rutine modificerer strengen (overført ByVal), så
oprettes der et nyt data-areal et eller andet sted i hukommelsen, og
pointeren bliver opdateret, så den peger på dette data-areal. Men da
det er pointeren, som er blevet overført ByVal, så ændrer dette ikke
på den oprindelige pointer i det kaldende program, den peger stadig
på det gamle data-areal. Der er altså 2 data-arealer og 2 pointere.
Et eksempel forklarer det nok bedre:
Dim Tekst As String
Tekst = "abc"
ModifyText Tekst
Print Tekst
Sub ModifyText(ByVal Tekst As String)
Tekst = "123"
End Sub
Når dette program køres, printer det "abc", som forventet.
Nu sætter vi nogle tal på:
Vi antager at sætningen 'Dim Tekst As String' allokerer 4 bytes i
hukommelsen på adresse 100.
Sætningen 'Tekst = "abc"' allokerer et data-areal på adresse 200, som
indeholder teksten "abc" (en nul-termineret unicode-streng). De 4 bytes
på adresse 100 får derefter indholdet 200 (pointer til data-arealet).
Når rutinen ModifyText kaldes, så overføres tallet 200 på stacken.
Underutinen har da adgang til data via denne pointer.
Når nu sætningen 'Tekst = "123"' udføres, så oprettes et nyt data-areal
på adresse 300 med indholdet "123" (igen en nul-termineret
unicode-streng), og pointeren PÅ STACKEN ændres til 300.
Når rutinen derefter returnerer, frigives data på adresse 300, og
tallet 300 fjernes fra stacken. Tilbage i hovedprogrammet, indeholder
adresse 100 stadig tallet 200, og adresse 200 indeholder stadig den
oprindelige tekst "abc".
Havde vi i stedet overført ByRef, så ville tallet 100 være blevet lagt
på stacken. Efter allokering af det nye data-areal på adresse 300, ville
adresse 100 få indholdet 300, og data på adresse 200 ville blive
frigivet (da der nu ikke er nogle referencer til dette areal).
Data på adresse 300 vil derimod ikke blive frigivet, da det jo er
refereret via adresse 100.
Når man modificerer en streng, ændrer man altså ikke i de eksisterende
data. Man opretter en ny streng, og modificerer pointeren.
Med API-kald er det lidt anderledes. API-funktioner arbejder på
ANSI-strenge (1 byte pr. tegn), mens VB arbejder på Unicode-strenge
(2 bytes pr. tegn). Her foretager VB en intern konvertering mellem de
to formater før og efter kaldet, så her bliver data altid kopieret
(også ved overførsel ByRef). Det er stadigvæk kun pointere, der
overføres, men nu er det bare en temporær ANSI-kopi der arbejdes på,
og det er den, som kan modificeres, hvis man overfører ByRef.
--
Posted via Mailgate.ORG Server - http://www.Mailgate.ORG
| |
Frank Bertelsen (25-01-2002)
| Kommentar Fra : Frank Bertelsen |
Dato : 25-01-02 15:49 |
|
> Overførsel ByVal tager altid en kopi af de pågældende data.
> Ikke af pointeren...
Nej, overførsel af strenge i VB foregår altid via pointere.
Der kopieres ingen data.
> Den eneste undtagelse er i forbindelse med API-kald, hvor ByVal vil overføre
> en pointer til de pågældende data.
Nej, ved API-kald bliver der netop taget en kopi af data, da VB altid
arbejder med strenge i Unicode, mens API-funktioner arbejder med
strenge i ANSI.
Jeg lyder måske meget skråsikker, men jeg har arbejdet meget med
overførsel af strenge mellem forskellige programmeringssprog, og
konvertering mellem Unicode og ANSI, så jeg ved hvordan det foregår.
Jeg er udmærket godt klar over, at en streng overført ByRef kan
modificeres i den kaldte rutine, det kan den ikke hvis den er overført
ByVal, men det betyder ikke at data nødvendigvis bliver kopieret.
Når den kaldte rutine modificerer strengen (overført ByVal), så
oprettes der et nyt data-areal et eller andet sted i hukommelsen, og
pointeren bliver opdateret, så den peger på dette data-areal. Men da
det er pointeren, som er blevet overført ByVal, så ændrer dette ikke
på den oprindelige pointer i det kaldende program, den peger stadig
på det gamle data-areal. Der er altså 2 data-arealer og 2 pointere.
Et eksempel forklarer det nok bedre:
Dim Tekst As String
Tekst = "abc"
ModifyText Tekst
Print Tekst
Sub ModifyText(ByVal Tekst As String)
Tekst = "123"
End Sub
Når dette program køres, printer det "abc", som forventet.
Nu sætter vi nogle tal på:
Vi antager at sætningen 'Dim Tekst As String' allokerer 4 bytes i
hukommelsen på adresse 100.
Sætningen 'Tekst = "abc"' allokerer et data-areal på adresse 200, som
indeholder teksten "abc" (en nul-termineret unicode-streng). De 4 bytes
på adresse 100 får derefter indholdet 200 (pointer til data-arealet).
Når rutinen ModifyText kaldes, så overføres tallet 200 på stacken.
Underutinen har da adgang til data via denne pointer.
Når nu sætningen 'Tekst = "123"' udføres, så oprettes et nyt data-areal
på adresse 300 med indholdet "123" (igen en nul-termineret
unicode-streng), og pointeren PÅ STACKEN ændres til 300.
Når rutinen derefter returnerer, frigives data på adresse 300, og
tallet 300 fjernes fra stacken. Tilbage i hovedprogrammet, indeholder
adresse 100 stadig tallet 200, og adresse 200 indeholder stadig den
oprindelige tekst "abc".
Havde vi i stedet overført ByRef, så ville tallet 100 være blevet lagt
på stacken. Efter allokering af det nye data-areal på adresse 300, ville
adresse 100 få indholdet 300, og data på adresse 200 ville blive
frigivet (da der nu ikke er nogle referencer til dette areal).
Data på adresse 300 vil derimod ikke blive frigivet, da det jo er
refereret via adresse 100.
Når man modificerer en streng, ændrer man altså ikke i de eksisterende
data. Man opretter en ny streng, og modificerer pointeren.
Med API-kald er det lidt anderledes. API-funktioner arbejder på
ANSI-strenge (1 byte pr. tegn), mens VB arbejder på Unicode-strenge
(2 bytes pr. tegn). Her foretager VB en intern konvertering mellem de
to formater før og efter kaldet, så her bliver data altid kopieret
(også ved overførsel ByRef). Det er stadigvæk kun pointere, der
overføres, men nu er det bare en temporær ANSI-kopi der arbejdes på,
og det er den, som kan modificeres, hvis man overfører ByRef.
En komplet beskrivelse af stenge i VB kan ses på følgende side:
http://www.oreilly.com/catalog/win32api/chapter/ch06.html
--
Posted via Mailgate.ORG Server - http://www.Mailgate.ORG
| |
Frank Bertelsen (25-01-2002)
| Kommentar Fra : Frank Bertelsen |
Dato : 25-01-02 16:46 |
|
> Overførsel ByVal tager altid en kopi af de pågældende data.
> Ikke af pointeren...
Nej, overførsel af strenge i VB foregår altid via pointere.
Der kopieres ingen data.
> Den eneste undtagelse er i forbindelse med API-kald, hvor ByVal vil overføre
> en pointer til de pågældende data.
Nej, ved API-kald bliver der netop taget en kopi af data, da VB altid
arbejder med strenge i Unicode, mens API-funktioner arbejder med
strenge i ANSI.
Jeg lyder måske meget skråsikker, men jeg har arbejdet meget med
overførsel af strenge mellem forskellige programmeringssprog, og
konvertering mellem Unicode og ANSI, så jeg ved hvordan det foregår.
Jeg er udmærket godt klar over, at en streng overført ByRef kan
modificeres i den kaldte rutine, det kan den ikke hvis den er overført
ByVal, men det betyder ikke at data nødvendigvis bliver kopieret.
Når den kaldte rutine modificerer strengen (overført ByVal), så
oprettes der et nyt data-areal et eller andet sted i hukommelsen, og
pointeren bliver opdateret, så den peger på dette data-areal. Men da
det er pointeren, som er blevet overført ByVal, så ændrer dette ikke
på den oprindelige pointer i det kaldende program, den peger stadig
på det gamle data-areal. Der er altså 2 data-arealer og 2 pointere.
Et eksempel forklarer det nok bedre:
Dim Tekst As String
Tekst = "abc"
ModifyText Tekst
Print Tekst
Sub ModifyText(ByVal Tekst As String)
Tekst = "123"
End Sub
Når dette program køres, printer det "abc", som forventet.
Nu sætter vi nogle tal på:
Vi antager at sætningen 'Dim Tekst As String' allokerer 4 bytes i
hukommelsen på adresse 100.
Sætningen 'Tekst = "abc"' allokerer et data-areal på adresse 200, som
indeholder teksten "abc" (en nul-termineret unicode-streng). De 4 bytes
på adresse 100 får derefter indholdet 200 (pointer til data-arealet).
Når rutinen ModifyText kaldes, så overføres tallet 200 på stacken.
Underutinen har da adgang til data via denne pointer.
Når nu sætningen 'Tekst = "123"' udføres, så oprettes et nyt data-areal
på adresse 300 med indholdet "123" (igen en nul-termineret
unicode-streng), og pointeren PÅ STACKEN ændres til 300.
Når rutinen derefter returnerer, frigives data på adresse 300, og
tallet 300 fjernes fra stacken. Tilbage i hovedprogrammet, indeholder
adresse 100 stadig tallet 200, og adresse 200 indeholder stadig den
oprindelige tekst "abc".
Havde vi i stedet overført ByRef, så ville tallet 100 være blevet lagt
på stacken. Efter allokering af det nye data-areal på adresse 300, ville
adresse 100 få indholdet 300, og data på adresse 200 ville blive
frigivet (da der nu ikke er nogle referencer til dette areal).
Data på adresse 300 vil derimod ikke blive frigivet, da det jo er
refereret via adresse 100.
Når man modificerer en streng, ændrer man altså ikke i de eksisterende
data. Man opretter en ny streng, og modificerer pointeren.
Med API-kald er det lidt anderledes. API-funktioner arbejder på
ANSI-strenge (1 byte pr. tegn), mens VB arbejder på Unicode-strenge
(2 bytes pr. tegn). Her foretager VB en intern konvertering mellem de
to formater før og efter kaldet, så her bliver data altid kopieret
(også ved overførsel ByRef). Det er stadigvæk kun pointere, der
overføres, men nu er det bare en temporær ANSI-kopi der arbejdes på,
og det er den, som kan modificeres, hvis man overfører ByRef.
En komplet beskrivelse af stenge i VB kan ses på følgende side:
http://www.oreilly.com/catalog/win32api/chapter/ch06.html
--
Posted via Mailgate.ORG Server - http://www.Mailgate.ORG
| |
Frank Bertelsen (25-01-2002)
| Kommentar Fra : Frank Bertelsen |
Dato : 25-01-02 15:53 |
|
Lidt om strenge i VB:
Når en rutine modificerer en streng, som er overført ByVal, så
oprettes der et nyt data-areal et eller andet sted i hukommelsen, og
pointeren bliver opdateret, så den peger på dette data-areal. Men da
det er pointeren, som er blevet overført ByVal, så ændrer dette ikke
på den oprindelige pointer i det kaldende program, den peger stadig
på det gamle data-areal. Der er altså 2 data-arealer og 2 pointere.
Et eksempel forklarer det nok bedre:
Dim Tekst As String
Tekst = "abc"
ModifyText Tekst
Print Tekst
Sub ModifyText(ByVal Tekst As String)
Tekst = "123"
End Sub
Når dette program køres, printer det "abc", som forventet.
Nu sætter vi nogle tal på:
Vi antager at sætningen 'Dim Tekst As String' allokerer 4 bytes i
hukommelsen på adresse 100.
Sætningen 'Tekst = "abc"' allokerer et data-areal på adresse 200, som
indeholder teksten "abc" (en nul-termineret unicode-streng). De 4 bytes
på adresse 100 får derefter indholdet 200 (pointer til data-arealet).
Når rutinen ModifyText kaldes, så overføres tallet 200 på stacken.
Underutinen har da adgang til data via denne pointer.
Når nu sætningen 'Tekst = "123"' udføres, så oprettes et nyt data-areal
på adresse 300 med indholdet "123" (igen en nul-termineret
unicode-streng), og pointeren PÅ STACKEN ændres til 300.
Når rutinen derefter returnerer, frigives data på adresse 300, og
tallet 300 fjernes fra stacken. Tilbage i hovedprogrammet, indeholder
adresse 100 stadig tallet 200, og adresse 200 indeholder stadig den
oprindelige tekst "abc".
Havde vi i stedet overført ByRef, så ville tallet 100 være blevet lagt
på stacken. Efter allokering af det nye data-areal på adresse 300, ville
adresse 100 få indholdet 300, og data på adresse 200 ville blive
frigivet (da der nu ikke er nogle referencer til dette areal).
Data på adresse 300 vil derimod ikke blive frigivet, da det jo er
refereret via adresse 100.
Når man modificerer en streng, ændrer man altså ikke i de eksisterende
data. Man opretter en ny streng, og modificerer pointeren.
Med API-kald er det lidt anderledes. API-funktioner arbejder på
ANSI-strenge (1 byte pr. tegn), mens VB arbejder på Unicode-strenge
(2 bytes pr. tegn). Her foretager VB en intern konvertering mellem de
to formater før og efter kaldet, så her bliver data altid kopieret
(også ved overførsel ByRef). Det er stadigvæk kun pointere, der
overføres, men nu er det bare en temporær ANSI-kopi der arbejdes på,
og det er den, som kan modificeres, hvis man overfører ByRef.
En komplet beskrivelse af stenge i VB kan ses på følgende side:
http://www.oreilly.com/catalog/win32api/chapter/ch06.html
--
Posted via Mailgate.ORG Server - http://www.Mailgate.ORG
| |
Tomas Christiansen (28-01-2002)
| Kommentar Fra : Tomas Christiansen |
Dato : 28-01-02 12:55 |
|
Frank Bertelsen skrev:
> Når en rutine modificerer en streng, som er overført ByVal, så
> oprettes der et nyt data-areal et eller andet sted i hukommelsen, og
> pointeren bliver opdateret, så den peger på dette data-areal. Men da
> det er pointeren, som er blevet overført ByVal, så ændrer dette ikke
> på den oprindelige pointer i det kaldende program, den peger stadig
> på det gamle data-areal. Der er altså 2 data-arealer og 2 pointere.
Nu fik jeg lidt tid til at se på hvad det egentlig er, som du har
skrevet, og jeg må have dig til at forklare mig en ting:
Ud fra det ovenstående, som vi overhovedet ikke kan være uenige om,
kan jeg ikke forstå det, som du skrev, nemlig:
> Det er nu ikke helt korrekt.
som en kommantar til min bemærkning:
> Hvis man f.eks. har en streng som indeholder 10
> kilobyte data, skal de 10 kilobyte kopieres til et andet sted i
> hukommelsen hvis man bruges ByVal.
Det hele skal ses i lyset af PERFORMANCE-betragtningen ved at overføre
"noget" ByVal eller ByRef.
Har jeg så ikke ret i, at der i forbindelse med en ByVal overførsel af
en streng på 10 kilobyte, skal kopieres 10 kilobyte data til et andet
sted i hukommelsen. At der så i VB's implementationen af en
ByVal-overførsel også indgår en pointer (det er vist en meget
almindelig måde at håndterere dette på), er i og for sig ligegyldigt?
PERFORMANCE "problemet" er da til stedet - pointer eller ej?
-------
Tomas
| |
Frank Bertelsen (28-01-2002)
| Kommentar Fra : Frank Bertelsen |
Dato : 28-01-02 17:01 |
|
Hej Thomas,
Hvis der ved parameteroverførsel af strenge ByVal kun overføres en
pointer, i stedet for at alle data koiperes, så har det da i høj grad
noget med performance at gøre.
ByVal betyder at indholdet af variablen overføres. En 'String'
indeholder kun en pointer, så det er den der overføres.
Hvis du har et dataareal på 10KB, og en pointer, der peger på dette
areal, så er der ingen grund til at tage en kopi af de 10KB data.
Pointeren placeres på stacken, og den kan underrutinen modificere så
meget den har lyst, det ændrer ikke ved den kaldende rutines pointer.
En ændring af data i underrutinen vil kun bevirke, at pointeren på
stacken ændres, så den peger på de nye data.
--
Posted via Mailgate.ORG Server - http://www.Mailgate.ORG
| |
Tomas Christiansen (28-01-2002)
| Kommentar Fra : Tomas Christiansen |
Dato : 28-01-02 22:59 |
|
Frank Bertelsen skrev:
> En ændring af data i underrutinen vil kun bevirke, at pointeren på
> stacken ændres, så den peger på de nye data.
Kan du så forklare mig hvorfor at f1 bruger dobbelt så meget RAM som
f2:
Sub f1(ByVal s As String)
MsgBox "Indholdet af s er nu en KOPI!!!"
End Sub
Sub f2(ByRef s As String)
MsgBox "s er IKKE en kopi her"
End Sub
når de bliver kaldt af følgende kodestump:
Dim s1 As String
s1 = Space(10000000)
f1 s1
f2 s1
Forskellen i memoryforbruget på f1 og f2 er netop 20000000 bytes -
svarende til 2 bytes pr. tegn (som forventet).
-------
Tomas
| |
|
|