Bonjour a tous
J'ai toujours vue le @ avant une variable.
Mais le ^ est parfois avant parfois après la variable.
Qu'elle est la différence et comment emploie-t-on @ et ^?
Merci d'avance
Bonjour a tous
J'ai toujours vue le @ avant une variable.
Mais le ^ est parfois avant parfois après la variable.
Qu'elle est la différence et comment emploie-t-on @ et ^?
Merci d'avance
@ est un raccourci pour la function Addr(), donc là pas de problème je pense.
^ est utilisé de deux façon par contre :
- après un pointeur pour atteindre la destination (ce qui se note "v->" en C se note "v^" en Pascal).
- devant un type pour déclarer un pointeur vers ce type (ce qui se note "char*" en C se note "^char" en Pascal)
NB: dans l'exemple ci-dessus, si k était un tableau dynamique @k donnerait l'adresse d'un pointeur vers le tableau et non l'adresse du premier élément qu'on peut atteindre par @k[0]
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 type PInteger = ^Integer; // pointeur vers un Integer var p1: PInteger; // variable de type pointeur vers un Integer p2: ^Integer; // idem i : Integer; // Integer statique j : Integer; // un autre entier k : array[1..6] of Integer; // un tableau de 6 entiers begin p1 := Addr(i); // p1 pointe sur i p2 := @i; // idem pour p2 p1^ := 1; // donne à i la valeur 1 Inc(p2^); // incrément i Inc(p2); // décale le pointeur de la taille de son type // en théorie p2 pointe donc maintenant sur j // mais rien ne le garantie ! // par contre ça fonctionne très bien sur un tableau, record... // pour lesquelles l'organisation mémoire est connue p2 := @k; // pointe sur le premier élément de k p2^ := 1; // lui donne la valeur 1 Inc(p2); // passe au deuxième élément de k Inc(p2, 2); // passe au 4ième (2ième + 2) p2^ := 5; // équivalent à k[4] := 5; end;
Merci Paul
J'ai tout compris ou presque :
J'essaie de recréer en partie du code que François Piette avait déjà donné pour transférer le contenu d'un string dans un autre ultrarapide et efficace, (dont j'efface un certain caractère si présent)
Y'a-t'il moyen de balayer la variable "Source" en incrémentant un pointeur?
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 function Efface(const Source:ansistring; const ceci:ansichar):ansistring; var s,d,d0:^ansichar; ls:integer; begin ls:=length(Source); SetLength(result,ls); d0:=@result[1];//pointe sur le premier élément d :=d0; for s := @source[1] to @source[1]+ls-1 do //Erreur la variable de contrôle de boucle FOR doit être de type ordinal if s^<>ceci then begin//contenu pointer par s <> ceci alors inc(d);//pointe sur le prochain élément d^:=s^;//transfert lélément end; setlength(result,d-d0);//redimensionne à la bonne dimension end;
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 function Efface(const Source:ansistring; const ceci:ansichar):ansistring; var s,d,d0:^ansichar; i,j,ls:integer; begin ls:=length(Source); SetLength(result,ls); d0:=@result[1];//pointe sur le premier élément d :=d0; s := @source[1]; j := 0; for i := 0 to ls-1 do // for sur un entier begin if s^<>ceci then begin//contenu pointer par s <> ceci alors inc(d);//pointe sur le prochain élément d^:=s^;//transfert lélément inc(j); end; inc(s); // incrémenter s (comme tu voulais le faire dans le for) end; setlength(result,j);//redimensionne à la bonne dimension // d-d0 pourrait être utilisé sous la forme Integer(d) - Integer(d0) // mais sous XE2 il faut utiliser NativeInt...il est plus simple d'utiliser "j" end;
Merci beaucoup Paul
L'algo original avait une faute...
Voici donc corriger en incluant ta suggestion
Est-ce qu'il y a moyen d'optimiser la routine?
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 (* Révision du code *) function Efface(const Source:ansistring; const ceci:ansichar):ansistring; var s,d,d0:^ansichar; i,ls:integer; begin ls:=length(Source); SetLength(result,ls); d0:=@result[1];//pointe sur le premier élément d :=d0; s := @source[1]; for i := 0 to ls-1 do begin// for sur un entier if s^<>ceci then begin//contenu pointer par s <> ceci alors (* Erreur il fallait intervertir les deux lignes suivantes mea culpa *) d^:=s^;//transfert lélément inc(d);//pointe sur le prochain élément (* Fin de l'erreur *) end; inc(s); // incrémenter s (comme tu voulais le faire dans le for) end; setlength(result,NativeInt(d)-NativeInt(d0));//redimensionne à la bonne dimension tel que tu l'as signalé //je préfère cette solution à l'incrémentation de j pour des raisons d'optimisation end;
Est que remplacer l'appel de la fonction par une procédure
soit :
donnerait des gains significatifs ?
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2 procedure Efface(const Source:ansistring; var result:string; const ceci:ansichar):ansistring;
Autrement dit : Est-ce qu'avec function le résultat doit être recopier une fois la routine effectué ?
Ou simplement c'est le pointeur de la variable qui pointe maintenant dans une autre zone mémoire ?
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2 s:=Efface(s, 'A'):
Ce qui donnerait dans les faits le même temps d'exécution pour la procédure
Merci encore
Si tu veux jouer à la performance extrème, on a déjà pas mal débattu pour une fonction similaire : Remplacement d'occurence de caractères ou Comment supprimer tous les caractères spéciaux d'une string ?
Le Dernier SetLength de Reduction sous D7, c'était extrément couteux !
En D2007 ou avec FastMM, c'est 100 fois plus rapide
En DXE2, avec l'UNICODE, je ne me lancerais plus dans ce genre de chose, bon semble ne gérer que le AnsiString, pense des affections entre String et AnsiString sous XE2, c'est réallocation et traduction en fonction du CodePage !
Donc mettre un string en var, ça ne passera pas du tout !
Pour la différence de performance entre procedure var et function, euh, ça m'intéresse, le result, je ne sais pas trop comme ça fonctionne
A part que le Result c'est sur le Registre EAX pour les entiers et pointeurs, tout en se rappelant que EAX contient aussi le 1er paramètre !
Ce qui en ASM permet de faire deux trois trucs sympa !
Pour D7, j'avais osé ceci (je ne l'ai testé qu'avec les variables locales)
Cela fonctionnait, comme le FreeMem n'indiquait pas la longueur à libérer, il n'y avait pas de soucis !
Bon, je l'ai juste pour le fun, jamais osé le faire en prod !
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 procedure ReduceStr(var S: string; NewLength: Integer); type PStrRec = ^StrRec; StrRec = packed record refCnt: Longint; length: Longint; end; var SMeta: PStrRec; begin SMeta := PStrRec(Integer(S) - SizeOf(StrRec)); if SMeta.refCnt < 0 then begin if NewLength < Length(S) then begin S[Succ(NewLength)] := #0; SMeta.length := NewLength; end; end else SetLength(S, NewLength); end;
Si ça peut intéresser des gens
Voici les résultats de plusieurs routines exécutées 16 fois sur la chaine résultante
Longueur initiale de la chaine: 268435456 caractères
Procédure________Durée(s)_______Longueur finale de la chaîne
StringReplace_____00:05:293_____268435424
Efface___________00:17:743_____233832448
Efface0__________00:18:758_____233832448
Efface1__________00:15:224_____233832448<-Championne
Efface2__________00:17:671_____233832448
Efface3__________00:17:682_____233832448
Conclusion :
1 - La boucle Pour(For) est pénalisante dans ce cas d'espèce
2 - Affecter une variable de travaille est pénalisant aussi bien en result qu'en paramètre
3 - Vaut mieux travailler directement dans la chaine que dans une copie (tiré de 2)
4 - StringReplace ne permet pas d'effacer une chaine sans laisser de trace
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
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183 function Efface0(const Source:ansistring; const ceci:ansichar):ansistring; var s,d,d0:^ansichar; i,ls:integer; begin ls:=length(Source); SetLength(result,ls); d0:=@result[1];//pointe sur le premier élément d :=d0; s := @source[1]; for i := 0 to ls-1 do begin// for sur un entier if s^<>ceci then begin//contenu pointer par s <> ceci alors d^:=s^;//transfert lélément inc(d);//pointe sur le prochain élément end; inc(s); // incrémenter s (comme tu voulais le faire dans le for) end; setlength(result,NativeInt(d)-NativeInt(d0){j});//redimensionne à la bonne dimension end; function Efface2(const Source:ansistring; const ceci:ansichar):ansistring; var s,sf,d,d0:^ansichar; i,ls,ld:integer; begin ls:=length(Source); SetLength(result,ls); d0:=@result[1];//pointe sur le premier élément d :=d0; s:=@source[1];//pointe sur le premier élément sf:=@source[ls]; inc(sf); while s<>sf do begin// sur un entier if s^<>ceci then begin//contenu pointer par s <> ceci alors d^:=s^;//transfert lélément inc(d);//pointe sur le prochain élément end; inc(s); // incrémenter s (comme tu voulais le faire dans le for) end; setlength(result,NativeInt(d)-NativeInt(d0){j});//redimensionne à la bonne dimension //result:=ls-ld; end; procedure Efface3(const Source:ansistring;var result:ansistring; const ceci:ansichar); var s,sf,d,d0:^ansichar; i,ls,ld:integer; begin ls:=length(Source); SetLength(result,ls); d0:=@result[1];//pointe sur le premier élément d :=d0; s:=@source[1];//pointe sur le premier élément sf:=@source[ls]; inc(sf); while s<>sf do begin// sur un entier if s^<>ceci then begin//contenu pointer par s <> ceci alors d^:=s^;//transfert lélément inc(d);//pointe sur le prochain élément end; inc(s); // incrémenter s (comme tu voulais le faire dans le for) end; setlength(result,NativeInt(d)-NativeInt(d0){j});//redimensionne à la bonne dimension //result:=ls-ld; end; function Efface(var Source:ansistring; const ceci:ansichar):integer; var s,d,d0:^ansichar; i,ls,ld:integer; begin ls:=length(Source); d0:=@source[1];//pointe sur le premier élément d :=d0; s :=d0; for i := 0 to ls-1 do begin// for sur un entier if s^<>ceci then begin//contenu pointer par s <> ceci alors d^:=s^;//transfert lélément inc(d);//pointe sur le prochain élément end; inc(s); // incrémenter s (comme tu voulais le faire dans le for) end; ld:=NativeInt(d)-NativeInt(d0); setlength(Source,ld);//redimensionne à la bonne dimension result:=ls-ld; end; function Efface1(var Source:ansistring; const ceci:ansichar):integer; var s,sf,d,d0:^ansichar; i,ls,ld:integer; begin ls:=length(Source); d0:=@source[1];//pointe sur le premier élément d :=d0; s :=d0; sf:=@source[ls]; inc(sf); while s<>sf do begin// sur un entier if s^<>ceci then begin//contenu pointer par s <> ceci alors d^:=s^;//transfert lélément inc(d);//pointe sur le prochain élément end; inc(s); // incrémenter s (comme tu voulais le faire dans le for) end; ld:=NativeInt(d)-NativeInt(d0); setlength(Source,ld);//redimensionne à la bonne dimension result:=ls-ld; end; procedure TForm1.Button2Click(Sender: TObject); const c='adsflhajsdfljhasdfljhasldkjf'; var s,t,longuechaine:ansistring; ans,vs:ansistring; l,x,i,puissance2:integer; p:tdate; begin setlength(longuechaine,1 shl 28);//prépare la chain for x:=1 to 1 shl 28 do longuechaine[x]:=ansichar(x and 255); puissance2:=5; memo1.Lines.Add(inttostr(length(longuechaine))); memo1.Lines.Add('Procedure Durée Longueur'); vs:=''; s:=longuechaine; p:=now; for I := 0 to 1 shl puissance2 do begin ans:=ansichar(i); s:=AnsiStrings.StringReplace(S, ans, vs,[rfReplaceAll]); end; p:=now-p; l:=length(s); memo1.Lines.Add('StringReplace '+ formatdatetime('nnsszzz',p)+' '+inttostr(l)); s:=longuechaine; p:=now; for I := 0 to 1 shl puissance2 do begin x:=efface(s,ansichar(i)); end; p:=now-p; l:=length(s); memo1.Lines.Add('Efface '+ formatdatetime('nnsszzz',p)+' '+inttostr(l)); s:=longuechaine; p:=now; for I := 0 to 1 shl puissance2 do begin s:=efface0(s,ansichar(i)); end; p:=now-p; l:=length(s); memo1.Lines.Add('Efface0 '+ formatdatetime('nnsszzz',p)+' '+inttostr(l)); s:=longuechaine; p:=now; for I := 0 to 1 shl puissance2 do begin x:=efface1(s,ansichar(i)); end; l:=length(s); p:=now-p; memo1.Lines.Add('Efface1 '+ formatdatetime('nnsszzz',p)+' '+inttostr(l)); s:=longuechaine; p:=now; for I := 0 to 1 shl puissance2 do begin s:=efface2(s,ansichar(i)); end; l:=length(s); p:=now-p; memo1.Lines.Add('Efface2 '+ formatdatetime('nnsszzz',p)+' '+inttostr(l)); t:=''; s:=longuechaine; p:=now; for I := 0 to 1 shl puissance2 do begin efface3(s,t,ansichar(i)); s:=t; end; p:=now-p; l:=length(t); memo1.Lines.Add('Efface3 '+ formatdatetime('nnsszzz',p)+' '+inttostr(l)); end;
Ajout
Si en premier l'algorithme ne fait que remplacer tout les caractères par un caractère unique. Et ensuite qu'on les efface on obtient un temps de
Remplace-Efface 00:13:524s 233832448
Ce qui logique
1-Marquer tout les caractères à effacer
2-Effacer les caractères marqués
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 procedure Remplace1(var Source:ansistring; const ceci,parca:ansichar); var s,sf,d,d0:^ansichar; i,ls,ld:integer; begin ls:=length(Source); s:=@source[1];//pointe sur le premier élément sf:=@source[ls]; inc(sf); while s<>sf do begin// sur un entier if s^=ceci then //contenu pointer par s = ceci alors s^:=parca;//transfert lélément inc(s); // incrémenter s end; end; procedure TForm1.Button2Click(Sender: TObject); ... s:=longuechaine; p:=now; for I := 0 to 1 shl puissance2 do begin remplace1(s,ansichar(i),ansichar(0)); end; x:=efface1(s,ansichar(0)); p:=now-p; l:=length(s); memo1.Lines.Add('Efface '+ formatdatetime('nnsszzz',p)+' '+inttostr(l)); ...
Premièrement, tu ne fais pas 16, mais 17 boucles
Deuxièmement, pourquoi n'essayes-tu pas des copies par bloque ?
Tu pourrais encore gagner du temps en augmentant la priorité du processus le temps de l'effacement.
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
37
38
39
40
41 function EffaceX(const aSource :AnsiString; const aChar :AnsiChar) :AnsiString; var P :PAnsiChar; PSource :PAnsiChar; PDest :PAnsiChar; PEnd :PAnsiChar; Len :integer; Size :integer; begin SetLength(Result, Length(aSource)); PSource := PAnsiChar(aSource); PEnd := PSource +Length(aSource); P := PSource; PDest := PAnsiChar(Result); Size := 0; while P < PEnd do begin if P^ = aChar then begin Len := P -PSource; CopyMemory(PDest, PSource, Len); inc(Size, Len); inc(PDest, Len); PSource := P +1; end; inc(P); end; if P <> PSource then begin Len := P -PSource; CopyMemory(PDest, PSource, Len); inc(Size, Len); end; SetLength(Result, Size); end;
Code : Sélectionner tout - Visualiser dans une fenêtre à part SetPriorityClass(GetCurrentProcess, REALTIME_PRIORITY_CLASS);
(Je suis un peu rouillé )
Merci pour le code je m'y attaquais ce matin
Résultat
J'ai du faire passer les boucle de 33 à 128 car trop serré
Chaine intiale 268435456 caractères
Procedure_____Durée______Longueur
EffaceX 00:47:457 133169152 <-Championne ?
Efface1 00:47:653 133169152
Merci ta routine va me simplifier la vie, car je n'aurais à maintenir des routines spécifiques.
De plus, Il doit avoir moyen d'améliorer ta routine en travaillant directement dans la chaine sans allocation de mémoire :
Résultat:
Chaine intiale 268435456 caractères
Procedure_____Durée______Longueur
Efface1_______00:47:515__134217728
EffaceX_______00:48:125__134217728
EffaceXPlus____00:39:985__134217728 <- Grande Championne
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
37
38
39
40
41 function EffaceXPlus(var aSource :AnsiString; const aChar :AnsiChar) :integer; var P :PAnsiChar; PSource :PAnsiChar; PDest :PAnsiChar; PEnd :PAnsiChar; Len :integer; Size :integer; La :integer; begin // SetLength(Result, Length(aSource)); La := Length(aSource); PSource := PAnsiChar(aSource); PEnd := PSource +La; P := PSource; PDest := Psource;//PAnsiChar(Result); Size := 0; while P < PEnd do begin if P^ = aChar then begin Len := P -PSource; CopyMemory(PDest, PSource, Len); inc(Size, Len); inc(PDest, Len); PSource := P +1; end; inc(P); end; if P <> PSource then begin Len := P -PSource; CopyMemory(PDest, PSource, Len); inc(Size, Len); end; SetLength(aSource, Size); Result:=La-size; end;
Bonne idée, mais il y a des applications qui ne doivent pas s'arrêter. Optimiser le jus tout en restant collaboratif
Est-ce que tu as sous la main routine remplaçant une chaine par une autre en utilisant des copies par bloc?
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