Nicky22
Messages postés4Date d'inscriptionvendredi 14 juillet 2006StatutMembreDernière intervention19 janvier 2009 19 janv. 2009 à 05:19
Re-salut BruNews, je n'avais pas vu votre pedigree... bravo !
Vous avez donc certainement de meilleures connaissances que moi en assembleur...
Du coup, j'ai eu un doute sur le nombre d'évaluations de strlen dans la boucle if.
Un petit bout de code de test m'a montré que vous aviez 100% raison.
Il vaut donc mieux remplacer mon code initial
for (i=0;i<strlen(sz);i++) { ... }
par
int n=strlen(sz);
for (i=0;i<n;i++) { ... }
A+
Nicky22
Messages postés4Date d'inscriptionvendredi 14 juillet 2006StatutMembreDernière intervention19 janvier 2009 19 janv. 2009 à 03:26
Merci BruNews de votre commentaire.
Il est toujours possible de coder de multiples manières... et en fonction du but recherché (intérêt pédagogique, efficacité, robustesse, rapidité d'écriture, lisibilité, portabilité, ré-utilisabilité, etc.), certains choix sont meilleurs que d'autres.
Mais vous énoncez quelques vérités qui ... ne le sont pas :
- écrire char XX[xx]={0} n'équivaut pas à un memset, mais force juste le 1er caractère de la chaine à zéro. En debug, la chaine est de toute façon toute mise à zéro, mais pas en release. J'ai pris cette bonne habitude d'initialiser systématiquement chaque variable il y a longtemps...et ne m'en suis jamais plaint (sauf dans certains cas d'optimisation).
- le strlen dans le test de la boucle "if" ne sera évalué qu'une seule fois.
- Un setup pour déployer les MFC est inutile si on compile le projet en release, mfc42.dll se trouve dans Windows depuis 95/98 (et pas mfc42d.dll, si compilé debug, je vous l'accorde). Enfin, si ça vous inquiète toujours, vous pouvez toujours faire un "static link" avec les .lib des MFC...
Enfin, dans le rayon goûts et couleurs,
- j'aime pas les goto en C, mais à chacun ses marottes !
- OK pour la "surcouche" des MFC, on perd sans doute un peu de perfos (mais sont-elles vraiment requises dans un programme de ce genre ?). Avantages : facilité d'écriture, robustesse et lisibilité (qualités primordiales dans l'industrie). Inconvénient majeur : portabilité.
Pour illustrer ce dernier propos, seriez-vous prêt à réécrire la fonction CString::Replace() juste pour optimiser le code ? D'un point de vue pédagogique, c'est assez intéressant, mais bon...
En tous cas, merci de m'avoir donné l'occasion de débattre avec vous.
Intéressant !
Amicalement / NC
BruNews
Messages postés21040Date d'inscriptionjeudi 23 janvier 2003StatutModérateurDernière intervention21 août 2019 18 janv. 2009 à 14:54
char szUpBuffer[1024]={0};
A quoi sert de forcer un memset() sur des buffers locaux ? à rien puisqu'on va y recopier des chaine qui ont donc un zero teminateur.
for(i 0; i < strlen(string) + 1; i++) szUpBuffer[i] (char)toupper(string[i]);
Recalcul strlen() à chaque tour ???
On remplacera par:
char *c, *d;
c = string;
d = szUpBuffer;
while(*c) *d++ = (char) toupper(*c++);
*d = 0;
On obtient donc:
LPCTSTR stristr(LPCTSTR string, LPCTSTR strCharSet)
{
char szUpBuffer[1024], szUpCharSet[127], *c, *d;
c = string;
d = szUpBuffer;
while(*c) *d++ = (char) toupper(*c++);
*d = 0;
c = strCharSet;
d = szUpCharSet;
while(*c) *d++ = (char) toupper(*c++);
*d = 0;
c = strstr(szUpBuffer, szUpCharSet);
if(!c) goto strEXIT;
c = string + (c - szUpBuffer);
strEXIT: return c;
}
Tout l'ensemble du code est à revoir sur ce modèle.
Autre sujet:
Pourquoi employer MFC (ou autre surcouche) pour un mini utilitaire de ce genre ?
Pour cause de MFC, il faut par force un setup pour le distribuer.
Il suffit de remplacer les CString et autres Ctrucmuche par un peu de code pour rendre l'exe indépendant.
gillardg
Messages postés3275Date d'inscriptionjeudi 3 avril 2008StatutMembreDernière intervention14 septembre 20142 17 janv. 2009 à 12:21
Nicky22
Messages postés4Date d'inscriptionvendredi 14 juillet 2006StatutMembreDernière intervention19 janvier 2009 16 janv. 2009 à 04:47
Petit bug expliquant le non-fonctionnement, comme vu sur la capture :
il fallait bien évidemment coder :
if (nDay < 1 || nDay >31) return CTime(0);
et non pas :
if (nDay <= 1 || nDay >31) return CTime(0);
19 janv. 2009 à 11:53
Il n'y a que le vieux VS6 pour linker avec MFC42, toute version ultérieure doit fournir un setup ou livrer un exe monumental.
TESTONS:
#define _WIN32_WINNT 0x0600
#define _WIN32_IE 0x0700
#include <windows.h>
char szappname[] = "chrTst";
void fncTst(VOID)
{
char buf[40] = {0};
buf[0] = 'a';
MessageBox(0, buf, szappname, 0);
}
#pragma comment(linker, "/entry:myWinMain")
__declspec(naked) void __stdcall myWinMain()
{
__asm {
call fncTst
call fncTst
push 0
call dword ptr ExitProcess
}
}
LISTING ASM DU COMPILO:
_buf$ = -40
_fncTst@0 PROC
sub esp, 40
; 10 : char buf[40] = {0};
push 39
lea eax, DWORD PTR _buf$[esp+45]
push 0
push eax
call _memset
add esp, 12
; 11 : buf[0] = 'a';
; 12 : MessageBox(0, buf, szappname, 0);
push 0
push OFFSET _szappname
lea ecx, DWORD PTR _buf$[esp+48]
push ecx
push 0
mov BYTE PTR _buf$[esp+56], 97
call DWORD PTR __imp__MessageBoxA@16
add esp, 40
ret 0
_fncTst@0 ENDP
EXE fait 5 Ko et appel memset() sans équivoque.
Avec:
void fncTst(VOID)
{
char buf[40];
buf[0] = 'a';
buf[1] = 0;
MessageBox(0, buf, szappname, 0);
}
ON OBTIENT:
_buf$ = -40
_fncTst@0 PROC
sub esp, 40
; 9 : char buf[40];
; 10 : buf[0] = 'a';
; 11 : buf[1] = 0;
; 12 : MessageBox(0, buf, szappname, 0);
push 0
push OFFSET _szappname
lea eax, DWORD PTR _buf$[esp+48]
push eax
push 0
mov BYTE PTR _buf$[esp+56], 97
mov BYTE PTR _buf$[esp+57], 0
call DWORD PTR __imp__MessageBoxA@16
add esp, 40
ret 0
_fncTst@0 ENDP
EXE = 2.5 Ko et code optimal, y a pas photo.
19 janv. 2009 à 05:19
Vous avez donc certainement de meilleures connaissances que moi en assembleur...
Du coup, j'ai eu un doute sur le nombre d'évaluations de strlen dans la boucle if.
Un petit bout de code de test m'a montré que vous aviez 100% raison.
Il vaut donc mieux remplacer mon code initial
for (i=0;i<strlen(sz);i++) { ... }
par
int n=strlen(sz);
for (i=0;i<n;i++) { ... }
A+
19 janv. 2009 à 03:26
Il est toujours possible de coder de multiples manières... et en fonction du but recherché (intérêt pédagogique, efficacité, robustesse, rapidité d'écriture, lisibilité, portabilité, ré-utilisabilité, etc.), certains choix sont meilleurs que d'autres.
Mais vous énoncez quelques vérités qui ... ne le sont pas :
- écrire char XX[xx]={0} n'équivaut pas à un memset, mais force juste le 1er caractère de la chaine à zéro. En debug, la chaine est de toute façon toute mise à zéro, mais pas en release. J'ai pris cette bonne habitude d'initialiser systématiquement chaque variable il y a longtemps...et ne m'en suis jamais plaint (sauf dans certains cas d'optimisation).
- le strlen dans le test de la boucle "if" ne sera évalué qu'une seule fois.
- Un setup pour déployer les MFC est inutile si on compile le projet en release, mfc42.dll se trouve dans Windows depuis 95/98 (et pas mfc42d.dll, si compilé debug, je vous l'accorde). Enfin, si ça vous inquiète toujours, vous pouvez toujours faire un "static link" avec les .lib des MFC...
Enfin, dans le rayon goûts et couleurs,
- j'aime pas les goto en C, mais à chacun ses marottes !
- OK pour la "surcouche" des MFC, on perd sans doute un peu de perfos (mais sont-elles vraiment requises dans un programme de ce genre ?). Avantages : facilité d'écriture, robustesse et lisibilité (qualités primordiales dans l'industrie). Inconvénient majeur : portabilité.
Pour illustrer ce dernier propos, seriez-vous prêt à réécrire la fonction CString::Replace() juste pour optimiser le code ? D'un point de vue pédagogique, c'est assez intéressant, mais bon...
En tous cas, merci de m'avoir donné l'occasion de débattre avec vous.
Intéressant !
Amicalement / NC
18 janv. 2009 à 14:54
LPCTSTR stristr(LPCTSTR string, LPCTSTR strCharSet)
{
char *pStr=NULL;
char szUpBuffer[1024]={0};
char szUpCharSet[127]={0};
UINT i;
for(i 0; i < strlen(string) + 1; i++) szUpBuffer[i] (char)toupper(string[i]);
for(i 0; i < strlen(strCharSet) + 1; i++) szUpCharSet[i] (char)toupper(strCharSet[i]);
pStr = strstr(szUpBuffer, szUpCharSet);
if(!pStr) return NULL;
i = pStr - szUpBuffer;
pStr = (char*) string+i;
return pStr;
}
char szUpBuffer[1024]={0};
A quoi sert de forcer un memset() sur des buffers locaux ? à rien puisqu'on va y recopier des chaine qui ont donc un zero teminateur.
for(i 0; i < strlen(string) + 1; i++) szUpBuffer[i] (char)toupper(string[i]);
Recalcul strlen() à chaque tour ???
On remplacera par:
char *c, *d;
c = string;
d = szUpBuffer;
while(*c) *d++ = (char) toupper(*c++);
*d = 0;
On obtient donc:
LPCTSTR stristr(LPCTSTR string, LPCTSTR strCharSet)
{
char szUpBuffer[1024], szUpCharSet[127], *c, *d;
c = string;
d = szUpBuffer;
while(*c) *d++ = (char) toupper(*c++);
*d = 0;
c = strCharSet;
d = szUpCharSet;
while(*c) *d++ = (char) toupper(*c++);
*d = 0;
c = strstr(szUpBuffer, szUpCharSet);
if(!c) goto strEXIT;
c = string + (c - szUpBuffer);
strEXIT: return c;
}
Tout l'ensemble du code est à revoir sur ce modèle.
Autre sujet:
Pourquoi employer MFC (ou autre surcouche) pour un mini utilitaire de ce genre ?
Pour cause de MFC, il faut par force un setup pour le distribuer.
Il suffit de remplacer les CString et autres Ctrucmuche par un peu de code pour rendre l'exe indépendant.
17 janv. 2009 à 12:21
http://sourceforge.net/projects/unxutils
16 janv. 2009 à 04:47
il fallait bien évidemment coder :
if (nDay < 1 || nDay >31) return CTime(0);
et non pas :
if (nDay <= 1 || nDay >31) return CTime(0);