cmp BYTE PTR [ecx], 32 ; 00000020H
push esi
mov eax, ecx
mov esi, ecx
jne SHORT $LN11@
npad 6
$LL7@:
add ecx, 1
cmp BYTE PTR [ecx], 32 ; 00000020H
je SHORT $LL7@
$LN11@:
mov dl, BYTE PTR [ecx]
test dl, dl
je SHORT $LN4@
npad 2
$LL5@:
add ecx, 1
mov BYTE PTR [eax], dl
mov dl, BYTE PTR [ecx]
add eax, 1
test dl, dl
jne SHORT $LL5@
$LN4@:
cmp eax, esi
pop esi
je SHORT $LN15@
$LL2@:
sub eax, 1
cmp BYTE PTR [eax], 32 ; 00000020H
je SHORT $LL2@
add eax, 1
$LN15@:
mov BYTE PTR [eax], 0
ret 0
Il génère bien un push.
BruNews
Messages postés21040Date d'inscriptionjeudi 23 janvier 2003StatutModérateurDernière intervention21 août 2019 31 juil. 2007 à 22:43
pas grave, facile à voir ce que serait dans un gros proj avec différents contextes d'appels:
__declspec(naked) char* __fastcall trim(char* psrc)
{
__asm {
cmp BYTE PTR[ecx], 32
mov eax, ecx
mov [esp-4], ecx
jne SHORT $LN11@trim
...
...
$LL5@trim:
add ecx, 1
mov BYTE PTR [eax], dl
mov dl, BYTE PTR [ecx]
add eax, 1
test dl, dl
jne SHORT $LL5@trim
cmp eax, [esp-4]
je SHORT $LN16@trim
$LL2@trim:
...
malheureusement c'est ce qu'on fait à la main, le compilo mettra un PUSH au lieu du [esp-4], il ne se permet jamais ce genre de fantaisie.
SAKingdom
Messages postés3212Date d'inscriptionlundi 7 novembre 2005StatutMembreDernière intervention16 février 200915 31 juil. 2007 à 22:33
Je n'y arrive pas. À tout les coups, il me remet le cmp [esi], 32.
BruNews
Messages postés21040Date d'inscriptionjeudi 23 janvier 2003StatutModérateurDernière intervention21 août 2019 31 juil. 2007 à 22:12
cmp BYTE PTR [esi], 32 ; 00000020H
ça ne t'alarme pas cette entrée ???
le compilo a inséré la fonction dans l'arbre d'optimisation (ceci dit c'est excellent) mais faut lui faire différents appels pour avoir la fonction bien indépendante pour en juger.
SAKingdom
Messages postés3212Date d'inscriptionlundi 7 novembre 2005StatutMembreDernière intervention16 février 200915 31 juil. 2007 à 22:07
revoici le listing avec un minimum d'indentation.
cmp BYTE PTR [esi], 32 ; 00000020H
mov eax, esi
mov ecx, esi
jne SHORT $LN11@trim
npad 7
$LL7@trim:
add ecx, 1
cmp BYTE PTR [ecx], 32 ; 00000020H
je SHORT $LL7@trim
$LN11@trim:
mov dl, BYTE PTR [ecx]
test dl, dl
je SHORT $LN16@trim
npad 2
$LL5@trim:
add ecx, 1
mov BYTE PTR [eax], dl
mov dl, BYTE PTR [ecx]
add eax, 1
test dl, dl
jne SHORT $LL5@trim
cmp eax, esi
je SHORT $LN16@trim
$LL2@trim:
sub eax, 1
cmp BYTE PTR [eax], 32 ; 00000020H
je SHORT $LL2@trim
add eax, 1
$LN16@trim:
mov BYTE PTR [eax], 0
ret 0
SAKingdom
Messages postés3212Date d'inscriptionlundi 7 novembre 2005StatutMembreDernière intervention16 février 200915 31 juil. 2007 à 22:04
release avec optimisation en faveur de la vitesse:
cmp BYTE PTR [esi], 32 ; 00000020H
mov eax, esi
mov ecx, esi
jne SHORT $LN11@trim
npad 7
$LL7@trim:
add ecx, 1
cmp BYTE PTR [ecx], 32 ; 00000020H
je SHORT $LL7@trim
$LN11@trim:
mov dl, BYTE PTR [ecx]
test dl, dl
je SHORT $LN16@trim
npad 2
$LL5@trim:
add ecx, 1
mov BYTE PTR [eax], dl
mov dl, BYTE PTR [ecx]
add eax, 1
test dl, dl
jne SHORT $LL5@trim
cmp eax, esi
je SHORT $LN16@trim
$LL2@trim:
sub eax, 1
cmp BYTE PTR [eax], 32 ; 00000020H
je SHORT $LL2@trim
add eax, 1
$LN16@trim:
mov BYTE PTR [eax], 0
ret 0
BruNews
Messages postés21040Date d'inscriptionjeudi 23 janvier 2003StatutModérateurDernière intervention21 août 2019 31 juil. 2007 à 21:58
on dirait bien.
vérifie ce que produit le compilo.
SAKingdom
Messages postés3212Date d'inscriptionlundi 7 novembre 2005StatutMembreDernière intervention16 février 200915 31 juil. 2007 à 21:49
Arff. Oui c'est vrai..
J'ai décortiqué ta fonction et voici le résultat:
BruNews
Messages postés21040Date d'inscriptionjeudi 23 janvier 2003StatutModérateurDernière intervention21 août 2019 31 juil. 2007 à 21:08
Pour ta derniere remarque, bien entendu faut pas y aller comme un sauvage, essaie ma func avec chaine vide, tu verras que n(ira pas hors plage.
BruNews
Messages postés21040Date d'inscriptionjeudi 23 janvier 2003StatutModérateurDernière intervention21 août 2019 31 juil. 2007 à 21:07
he he, faut pas regarder le listing C pour juger des perfs.
Tu fais des trim en rafale sur des champs de BDD, 255 char par champ text, si on a 20 blancs au début (deja bien)
avec: if(*c++ !t) d c;
tu vas générer encore 235 sauts internes à la boucle, c'est mortel pour les perfs.
SAKingdom
Messages postés3212Date d'inscriptionlundi 7 novembre 2005StatutMembreDernière intervention16 février 200915 31 juil. 2007 à 21:05
On évite aussi de reculer en dehors de la zone mémoire comme pour cette chaine:
char test[] = " ";
Même si les probabilités sont faible, il se pourrait que test-1 soit un espace.
SAKingdom
Messages postés3212Date d'inscriptionlundi 7 novembre 2005StatutMembreDernière intervention16 février 200915 31 juil. 2007 à 21:03
Ben, c'est justement pour ne pas reculer que j'ai ajouté
if(*c++ !t) d c;
Suffis simplement de faire *d = 0 et hop c'est fait:
while(*str == t) str++;
while(*c = *str++)
if(*c++ !t) d c;
*d = 0; // Ici, d devrais pointer sur la fin+1 de la chaine valide, donc sur un espace
return d; // Retour sur 0 de fin de chaine
}
C'est pas mieux comme ça ?
BruNews
Messages postés21040Date d'inscriptionjeudi 23 janvier 2003StatutModérateurDernière intervention21 août 2019 31 juil. 2007 à 20:53
je ne saisis pas bien l'affaire:
while(*str == t) str++; ici ok
ensuite: while(*c = *str++) c++; suffit pour copie
ne reste plus qu'à reculer *c tant que == t, avant de lui mettre un 0.
SAKingdom
Messages postés3212Date d'inscriptionlundi 7 novembre 2005StatutMembreDernière intervention16 février 200915 31 juil. 2007 à 20:50
Oups, c'est un lea et non un mov.
J'avais testé avec un malloc et il stockait sa valeur de retour dans esi. Ça générait donc mov ecx, esi.
SAKingdom
Messages postés3212Date d'inscriptionlundi 7 novembre 2005StatutMembreDernière intervention16 février 200915 31 juil. 2007 à 20:46
C'est en release avec optimisation pour la vitesse.
SAKingdom
Messages postés3212Date d'inscriptionlundi 7 novembre 2005StatutMembreDernière intervention16 février 200915 31 juil. 2007 à 20:44
SAKingdom
Messages postés3212Date d'inscriptionlundi 7 novembre 2005StatutMembreDernière intervention16 février 200915 31 juil. 2007 à 20:34
Sur ce code:
int main (void)
{
char test[] = " Bonjour ";
bntrim(test);
printf("%s-fin", test);
return 0;
}
Fonctionne bien.
Génère bien un mov ecx, xxx à l'appel.
Je préfère moi aussi le mov au push. Pas besoin d'extraire la valeur du stack dans la fonction.
BruNews
Messages postés21040Date d'inscriptionjeudi 23 janvier 2003StatutModérateurDernière intervention21 août 2019 31 juil. 2007 à 20:25
Pour ce qui est de la fonction de la source, il est clair que c'est un exxemple complet de bug. Dépêchons nous de discuter ici dans les comments, je sens que l'ensemble disparaitra sous peu.
BruNews
Messages postés21040Date d'inscriptionjeudi 23 janvier 2003StatutModérateurDernière intervention21 août 2019 31 juil. 2007 à 20:23
Essaie fastcall en C et tu nous diras, pas testé.
Je préfère de loin MOV à PUSH.
Retourner ce qu'on passe à la fonction, aucun intérêt d'après moi puisqu'on l'a déjà.
SAKingdom
Messages postés3212Date d'inscriptionlundi 7 novembre 2005StatutMembreDernière intervention16 février 200915 31 juil. 2007 à 20:18
vicenzo >> Ah ok. J'me disais aussi.
SAKingdom
Messages postés3212Date d'inscriptionlundi 7 novembre 2005StatutMembreDernière intervention16 février 200915 31 juil. 2007 à 20:16
héhéhé.
Ben c'est sûr qu'en __fastcall ...
Mais il y a tout de même un mov ecx, xxx :P
cs_vicenzo
Messages postés178Date d'inscriptionmardi 16 août 2005StatutMembreDernière intervention25 août 20101 31 juil. 2007 à 20:13
ok pour le retour sur fin de chaine mais je trouve que lors d'un trim il est beaucoup plus utile de retourner le pointeur intial afin de pourvoir utliser la valeur de retour pour un strcpy, etc... De pus cela reste plus cohérent avec le reste de la lib C...
Pour la modif du pointeur interne, je parlai de la fonction Trim() de darkpoulpo de cette source. Il passe en param un char** et modifie sa valeur dans la fonction. Donc si le char * est alloué par malloc et que l'on utilise ce char* avec le Trim de darkpoulpo en passant son adresse et que ensuite on désallloue le char * : Bingo : erreur !
BruNews
Messages postés21040Date d'inscriptionjeudi 23 janvier 2003StatutModérateurDernière intervention21 août 2019 31 juil. 2007 à 20:10
Quelle prise de tête pour un banal trim.
Je vous ai fourni une version sans un seul push, que soit à l'appel ou en interne, ne reste qu'à l'utiliser.
SAKingdom
Messages postés3212Date d'inscriptionlundi 7 novembre 2005StatutMembreDernière intervention16 février 200915 31 juil. 2007 à 19:36
Le retour sur le 0 de fin de chaine est voulu. Permet un chainage direct si, par exemple, on fait un strcat après. Permet aussi d'avoir le nombre de char présent dans la chaine:
char *c = " Bonjour ";
int i = trimc(c, ' ')-c;
À utiliser comme bon te semblera.
Pour ce qui est de modifier le pointeur en interne, je n'est jamais eu de problème avec ça.
J'ai essayer ceci juste au cas où:
char *test = (char*)malloc(255);
et tout fonctionne parfaitement. test pointe toujours au même endroit du début à la fin.
J'ai jeté un coup d'oeil au listing. Voici un abrégé de ce qui ce passe (fonction en __stdcall):
// Appel de la fonction
// On met les valeurs sur le stack
push 32 // c'est l'espace
push ecx // dison qu'ecx contient l'adresse du pointeur
call trimc
//dans trimc
mov ebx, [ebp] // on met le contenue de ebp dans ebx
// On travaillera donc sur ebx et sur le stack
En gros, on travail sur une copie du pointeur qui est sur le stack et non le pointeur lui-même. L'original ne devrait donc pas être altéré. ecx devrait donc toujours pointer au bon endroit après l'appel.
Va voir le listing d'un code, je crois que ça t'expliquera bien mieux que moi.
J'espère que je n'est pas dis de conneries.
cs_vicenzo
Messages postés178Date d'inscriptionmardi 16 août 2005StatutMembreDernière intervention25 août 20101 31 juil. 2007 à 19:06
La motivation de mon commentaire initial (hormis faire refroidir mon café trop chaud) était de mettre en évidence le fait que la fonction retournait un pointeur différent de celui fournit (ce qui n'est pas robuste et source de bug) et le fait que de modifier le pointeur en interne dans la fonction rend sa délallocation pontentiellement suicidaire
cs_vicenzo
Messages postés178Date d'inscriptionmardi 16 août 2005StatutMembreDernière intervention25 août 20101 31 juil. 2007 à 19:00
Salut SAKindom,
pour le rtrim, ok le café avait déja perdu 1°C - j'étais pressé de le déguster.
on trimmme à gauche, à droite, ou des deux, j'avais donc deux primitives rassemblées pour en faire un troisieme..
Effectivement cela toujours plus optimisé sans les deux sous appels
Sinon la valeur de retour n'est pas bonne car tu utilise c dans le code est donc tu ne retournes pas la valeur de départ..
SAKingdom
Messages postés3212Date d'inscriptionlundi 7 novembre 2005StatutMembreDernière intervention16 février 200915 31 juil. 2007 à 18:14
Salut vicenzo.
Hmmm, ton rtrimc n'est pas bon. Il remplace tout les espaces par des 0 à partir du début de la chaine. Utilisé après un ltrimc, on ne verra pas la différence mais si on l'utilise seul, adieu la chaine.
Ceci est fonctionnel:
Par la même occation, ton trim se trouve à parcourir 2 fois la chaine. 1 pour les ltrimc est 1 autre fois pour le rtrimc.
Ce trimc est fonctionnel (pas testé en profondeur):
J'espère que j'ai pas fais trop d'erreurs, car comme de disais, je n'est pas eu le temps de tout tester minutieusement.
cs_vicenzo
Messages postés178Date d'inscriptionmardi 16 août 2005StatutMembreDernière intervention25 août 20101 31 juil. 2007 à 17:14
Bon, pour la forme afin de faire un peu tiedir le café, voici un trim fait à la à volée pour expliciter mon propos.
le code est ecrit à l 'arrache (le café froid, c'est pas bon) et sans aucune contrôle mais il trimme bien avec décalage vers la gauche
cs_vicenzo
Messages postés178Date d'inscriptionmardi 16 août 2005StatutMembreDernière intervention25 août 20101 31 juil. 2007 à 16:39
Cette implémentation est dangeureuse car si ton pointeur avait alloué par un malloc, pour le free c'est foutu, puisque ton pointeur ne point plus sur la même adresse après l'appel.
un trim consiste en un trim gauche et un trim droite. A droite c'est simple, mais à gauche il ne faut pas se contenter de déplacer le pointeur il faut décaler les valeurs afin de garder la même adresse de départ.
Pour une implémentation robuste, toujours retourner le pointeur passé en paramètre car tu n'a aucune idée de la manière dont il a été alloué.
31 juil. 2007 à 23:44
Adaptation manuelle donne:
__declspec(naked) int __fastcall bntrim(char* psrc)
{ // ECX = psrc , RETOURNE NBR DE CHAR RESTANT
__asm {
mov eax, ecx
mov [esp-4], ecx
cmp byte ptr[eax], 32
jne short gEND
Ltrm1:
add ecx, 1
cmp byte ptr[ecx], 32
je short Ltrm1
gEND:
sub eax, 1
Ltrm2:
mov dl, [ecx]
add eax, 1
add ecx, 1
mov [eax], dl
test dl, dl
jnz short Ltrm2
mov ecx, [esp-4]
cmp eax, ecx
jna short Ltrm4
Ltrm3:
sub eax, 1
cmp byte ptr[eax], 32
je short Ltrm3
add eax, 1
Ltrm4:
mov byte ptr[eax], 0
sub eax, ecx
ret 0
}
}
c'est très bon.
Je préfère le nbr de char restant dans le cas d'un trim, me sert beaucoup plus dans mon taf.
31 juil. 2007 à 23:35
char *d = str;
du code C.
31 juil. 2007 à 23:03
Tu ne pourras pas empêcher cela sans faire l'asm manuel.
31 juil. 2007 à 22:53
31 juil. 2007 à 22:52
31 juil. 2007 à 22:51
char * __fastcall trim (char *str)
{
char *c str, *d str;
while(*str == ' ') str++;
while(*str) *c++ = *str++;
if(c != d) {
while(*--c == ' ');
c++;
}
*c = 0;
return c;
}
cmp BYTE PTR [ecx], 32 ; 00000020H
push esi
mov eax, ecx
mov esi, ecx
jne SHORT $LN11@
npad 6
$LL7@:
add ecx, 1
cmp BYTE PTR [ecx], 32 ; 00000020H
je SHORT $LL7@
$LN11@:
mov dl, BYTE PTR [ecx]
test dl, dl
je SHORT $LN4@
npad 2
$LL5@:
add ecx, 1
mov BYTE PTR [eax], dl
mov dl, BYTE PTR [ecx]
add eax, 1
test dl, dl
jne SHORT $LL5@
$LN4@:
cmp eax, esi
pop esi
je SHORT $LN15@
$LL2@:
sub eax, 1
cmp BYTE PTR [eax], 32 ; 00000020H
je SHORT $LL2@
add eax, 1
$LN15@:
mov BYTE PTR [eax], 0
ret 0
Il génère bien un push.
31 juil. 2007 à 22:43
__declspec(naked) char* __fastcall trim(char* psrc)
{
__asm {
cmp BYTE PTR[ecx], 32
mov eax, ecx
mov [esp-4], ecx
jne SHORT $LN11@trim
...
...
$LL5@trim:
add ecx, 1
mov BYTE PTR [eax], dl
mov dl, BYTE PTR [ecx]
add eax, 1
test dl, dl
jne SHORT $LL5@trim
cmp eax, [esp-4]
je SHORT $LN16@trim
$LL2@trim:
...
malheureusement c'est ce qu'on fait à la main, le compilo mettra un PUSH au lieu du [esp-4], il ne se permet jamais ce genre de fantaisie.
31 juil. 2007 à 22:33
31 juil. 2007 à 22:12
ça ne t'alarme pas cette entrée ???
le compilo a inséré la fonction dans l'arbre d'optimisation (ceci dit c'est excellent) mais faut lui faire différents appels pour avoir la fonction bien indépendante pour en juger.
31 juil. 2007 à 22:07
cmp BYTE PTR [esi], 32 ; 00000020H
mov eax, esi
mov ecx, esi
jne SHORT $LN11@trim
npad 7
$LL7@trim:
add ecx, 1
cmp BYTE PTR [ecx], 32 ; 00000020H
je SHORT $LL7@trim
$LN11@trim:
mov dl, BYTE PTR [ecx]
test dl, dl
je SHORT $LN16@trim
npad 2
$LL5@trim:
add ecx, 1
mov BYTE PTR [eax], dl
mov dl, BYTE PTR [ecx]
add eax, 1
test dl, dl
jne SHORT $LL5@trim
cmp eax, esi
je SHORT $LN16@trim
$LL2@trim:
sub eax, 1
cmp BYTE PTR [eax], 32 ; 00000020H
je SHORT $LL2@trim
add eax, 1
$LN16@trim:
mov BYTE PTR [eax], 0
ret 0
31 juil. 2007 à 22:04
cmp BYTE PTR [esi], 32 ; 00000020H
mov eax, esi
mov ecx, esi
jne SHORT $LN11@trim
npad 7
$LL7@trim:
add ecx, 1
cmp BYTE PTR [ecx], 32 ; 00000020H
je SHORT $LL7@trim
$LN11@trim:
mov dl, BYTE PTR [ecx]
test dl, dl
je SHORT $LN16@trim
npad 2
$LL5@trim:
add ecx, 1
mov BYTE PTR [eax], dl
mov dl, BYTE PTR [ecx]
add eax, 1
test dl, dl
jne SHORT $LL5@trim
cmp eax, esi
je SHORT $LN16@trim
$LL2@trim:
sub eax, 1
cmp BYTE PTR [eax], 32 ; 00000020H
je SHORT $LL2@trim
add eax, 1
$LN16@trim:
mov BYTE PTR [eax], 0
ret 0
31 juil. 2007 à 21:58
vérifie ce que produit le compilo.
31 juil. 2007 à 21:49
J'ai décortiqué ta fonction et voici le résultat:
char *trim (char *str)
{
char *c str, *d str;
while(*d == ' ') d++;
while(*d) *c++ = *d++;
if(c != str) {
while(*--c == ' ');
c++;
}
*c = 0;
return c; // Retour sur 0 de fin de chaine
}
C'est bon ça ?
31 juil. 2007 à 21:08
31 juil. 2007 à 21:07
Tu fais des trim en rafale sur des champs de BDD, 255 char par champ text, si on a 20 blancs au début (deja bien)
avec: if(*c++ !t) d c;
tu vas générer encore 235 sauts internes à la boucle, c'est mortel pour les perfs.
31 juil. 2007 à 21:05
char test[] = " ";
Même si les probabilités sont faible, il se pourrait que test-1 soit un espace.
31 juil. 2007 à 21:03
if(*c++ !t) d c;
Suffis simplement de faire *d = 0 et hop c'est fait:
char* trimc(char *str, char t)
{
char *c str, *d str;
while(*str == t) str++;
while(*c = *str++)
if(*c++ !t) d c;
*d = 0; // Ici, d devrais pointer sur la fin+1 de la chaine valide, donc sur un espace
return d; // Retour sur 0 de fin de chaine
}
C'est pas mieux comme ça ?
31 juil. 2007 à 20:53
while(*str == t) str++; ici ok
ensuite: while(*c = *str++) c++; suffit pour copie
ne reste plus qu'à reculer *c tant que == t, avant de lui mettre un 0.
31 juil. 2007 à 20:50
J'avais testé avec un malloc et il stockait sa valeur de retour dans esi. Ça générait donc mov ecx, esi.
31 juil. 2007 à 20:46
31 juil. 2007 à 20:44
char* trimc(char *str, char t)
{
char *c str, *d str;
while(*str == t) str++;
while(*str) {
*c = *str++;
if(*c++ !t) d c;
}
*d = 0;
return d; // Retour sur 0 de fin de chaine
}
Aussi, voici le listing de la fonction main:
sub esp, 16 ; 00000010H
mov eax, DWORD PTR ??_C@_0N@IIHOOOEL@?5?5Bonjour?5?5?5?$AA@
mov ecx, DWORD PTR ??_C@_0N@IIHOOOEL@?5?5Bonjour?5?5?5?$AA@+4
mov edx, DWORD PTR ??_C@_0N@IIHOOOEL@?5?5Bonjour?5?5?5?$AA@+8
mov DWORD PTR _test$[esp+16], eax
mov al, BYTE PTR ??_C@_0N@IIHOOOEL@?5?5Bonjour?5?5?5?$AA@+12
mov DWORD PTR _test$[esp+20], ecx
lea ecx, DWORD PTR _test$[esp+16]
mov DWORD PTR _test$[esp+24], edx
mov BYTE PTR _test$[esp+28], al
call @bntrim@4
lea ecx, DWORD PTR _test$[esp+16]
push ecx
push OFFSET ??_C@_06OJMELMDJ@?$CFs?9fin?$AA@
call _printf
xor eax, eax
add esp, 24 ; 00000018H
ret 0
31 juil. 2007 à 20:34
int main (void)
{
char test[] = " Bonjour ";
bntrim(test);
printf("%s-fin", test);
return 0;
}
Fonctionne bien.
Génère bien un mov ecx, xxx à l'appel.
Je préfère moi aussi le mov au push. Pas besoin d'extraire la valeur du stack dans la fonction.
31 juil. 2007 à 20:25
31 juil. 2007 à 20:23
Je préfère de loin MOV à PUSH.
Retourner ce qu'on passe à la fonction, aucun intérêt d'après moi puisqu'on l'a déjà.
31 juil. 2007 à 20:18
31 juil. 2007 à 20:16
Ben c'est sûr qu'en __fastcall ...
Mais il y a tout de même un mov ecx, xxx :P
31 juil. 2007 à 20:13
Pour la modif du pointeur interne, je parlai de la fonction Trim() de darkpoulpo de cette source. Il passe en param un char** et modifie sa valeur dans la fonction. Donc si le char * est alloué par malloc et que l'on utilise ce char* avec le Trim de darkpoulpo en passant son adresse et que ensuite on désallloue le char * : Bingo : erreur !
31 juil. 2007 à 20:10
Je vous ai fourni une version sans un seul push, que soit à l'appel ou en interne, ne reste qu'à l'utiliser.
31 juil. 2007 à 19:36
char *c = " Bonjour ";
int i = trimc(c, ' ')-c;
À utiliser comme bon te semblera.
Pour ce qui est de modifier le pointeur en interne, je n'est jamais eu de problème avec ça.
J'ai essayer ceci juste au cas où:
char *test = (char*)malloc(255);
strcpy(test, " bonjour ");
trimc(test, ' ');
printf("%s\n", test);
free(test);
et tout fonctionne parfaitement. test pointe toujours au même endroit du début à la fin.
J'ai jeté un coup d'oeil au listing. Voici un abrégé de ce qui ce passe (fonction en __stdcall):
// Appel de la fonction
// On met les valeurs sur le stack
push 32 // c'est l'espace
push ecx // dison qu'ecx contient l'adresse du pointeur
call trimc
//dans trimc
mov ebx, [ebp] // on met le contenue de ebp dans ebx
// On travaillera donc sur ebx et sur le stack
En gros, on travail sur une copie du pointeur qui est sur le stack et non le pointeur lui-même. L'original ne devrait donc pas être altéré. ecx devrait donc toujours pointer au bon endroit après l'appel.
Va voir le listing d'un code, je crois que ça t'expliquera bien mieux que moi.
J'espère que je n'est pas dis de conneries.
31 juil. 2007 à 19:06
31 juil. 2007 à 19:00
pour le rtrim, ok le café avait déja perdu 1°C - j'étais pressé de le déguster.
on trimmme à gauche, à droite, ou des deux, j'avais donc deux primitives rassemblées pour en faire un troisieme..
Effectivement cela toujours plus optimisé sans les deux sous appels
Sinon la valeur de retour n'est pas bonne car tu utilise c dans le code est donc tu ne retournes pas la valeur de départ..
Au final voila le code pour DarkPoulpos :
char* trimc(char *str, char t)
{
char *s1=str, *s2=str;
while(*s2 == t) s2++;
while(*s2) *s1++ = *s2++;
while (*--s1 == t);
*++s1 = 0;
return str;
}
31 juil. 2007 à 18:42
char* trimc(char *str, char t)
{
char *c str, *d str;
while(*str == t) str++;
while(*str) {
*c = *str++;
if(*c++ !t) d c;
}
*d = 0;
return d; // Retour sur 0 de fin de chaine
}
char* rtrimc(char *str, char t)
{
char *c = str;
while(*str) if(*str++ !t) c str;
*c = 0;
return c; // Retour sur 0 de fin de chaine
}
31 juil. 2007 à 18:14
Hmmm, ton rtrimc n'est pas bon. Il remplace tout les espaces par des 0 à partir du début de la chaine. Utilisé après un ltrimc, on ne verra pas la différence mais si on l'utilise seul, adieu la chaine.
Ceci est fonctionnel:
char* rtrimc(char *str, char t)
{
while(*str) str++;
while (*--str == t);
*++str = 0;
return str; // Retour sur 0 de fin de chaine
}
Par la même occation, ton trim se trouve à parcourir 2 fois la chaine. 1 pour les ltrimc est 1 autre fois pour le rtrimc.
Ce trimc est fonctionnel (pas testé en profondeur):
char* trimc(char *str, char t)
{
char *c = str;
while(*str == t) str++;
while(*str) *c++ = *str++;
while (*--c == t);
*++c = 0;
return c; // Retour sur 0 de fin de chaine
}
J'espère que j'ai pas fais trop d'erreurs, car comme de disais, je n'est pas eu le temps de tout tester minutieusement.
31 juil. 2007 à 17:14
le code est ecrit à l 'arrache (le café froid, c'est pas bon) et sans aucune contrôle mais il trimme bien avec décalage vers la gauche
#define trim(s) trimc(s, ' ')
#define rtrim(s) rtrimc(s, ' ')
#define ltrim(s) ltrimc(s, ' ')
char* trimc(char* s, char t)
{
rtrimc(s, t);
ltrimc(s, t);
return s;
}
char* rtrimc(char* str, char t)
{
char *s = str;
while (*s)
if (*s++==t)
{
*--s=0;
break;
}
return str;
}
char* ltrimc(char* str, char t)
{
if (*str == t)
{
char *s1=str, *s2=str;
while (*s2 == t) s2++;
while (*s2) *s1++ = *s2++;
*s1 = 0;
}
return str;
}
31 juil. 2007 à 16:39
un trim consiste en un trim gauche et un trim droite. A droite c'est simple, mais à gauche il ne faut pas se contenter de déplacer le pointeur il faut décaler les valeurs afin de garder la même adresse de départ.
Pour une implémentation robuste, toujours retourner le pointeur passé en paramètre car tu n'a aucune idée de la manière dont il a été alloué.