IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

C Discussion :

l'utilité d'utiliser les Booleens


Sujet :

C

  1. #21
    Expert confirmé

    Profil pro
    Inscrit en
    Janvier 2007
    Messages
    10 610
    Détails du profil
    Informations personnelles :
    Âge : 67
    Localisation : France

    Informations forums :
    Inscription : Janvier 2007
    Messages : 10 610
    Billets dans le blog
    2
    Par défaut
    Citation Envoyé par Melem Voir le message
    mais en tout cas je ne crois pas que quelqu'un puisse être assez ouf pour écrire if (... == TRUE)
    Le thème c'est sur les booléens non?
    tu as tort sur ce point...

    Vu que tout dépend de la définition de la norme et, dans le cas où elle ne le précise pas, de la définition de l'implémentation, il se peut parfaitement que

    TRUE soit définie
    et FALSE soit NON TRUE

    ou que

    FALSE soit défini
    et TRUE soit NON FALSE

    et donc on peut avoir les 2 types de tests..

    if ( ... == FALSE )

    ou

    if ( ..... == TRUE )


    Comme dit plus haut, la seule chose en C est que la plupart des fonctions "standards" retournent 0 en cas d'échec, mais par exemple main() a la convention inverse....

  2. #22
    Expert éminent
    Avatar de Médinoc
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Septembre 2005
    Messages
    27 391
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 41
    Localisation : France

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Septembre 2005
    Messages : 27 391
    Par défaut
    Euh...
    Quelle "plupart" exactement ?

    Les fonctions d'entrées/sortie retournent généralement EOF sur un échec, malloc() ne retourne pas un entier mais un pointeur (donc le "0" a une toute autre signification)...
    SVP, pas de questions techniques par MP. Surtout si je ne vous ai jamais parlé avant.

    "Aw, come on, who would be so stupid as to insert a cast to make an error go away without actually fixing the error?"
    Apparently everyone.
    -- Raymond Chen.
    Traduction obligatoire: "Oh, voyons, qui serait assez stupide pour mettre un cast pour faire disparaitre un message d'erreur sans vraiment corriger l'erreur?" - Apparemment, tout le monde. -- Raymond Chen.

  3. #23
    Expert confirmé
    Avatar de Melem
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Janvier 2006
    Messages
    3 656
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 39
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : High Tech - Électronique et micro-électronique

    Informations forums :
    Inscription : Janvier 2006
    Messages : 3 656
    Par défaut
    Citation Envoyé par Melem
    mais en tout cas je ne crois pas que quelqu'un puisse être assez ouf pour écrire if (... == TRUE)
    Le thème c'est sur les booléens non?
    tu as tort sur ce point...

    Vu que tout dépend de la définition de la norme et, dans le cas où elle ne le précise pas, de la définition de l'implémentation, il se peut parfaitement que

    TRUE soit définie
    et FALSE soit NON TRUE

    ou que

    FALSE soit défini
    et TRUE soit NON FALSE

    et donc on peut avoir les 2 types de tests..

    if ( ... == FALSE )

    ou

    if ( ..... == TRUE )
    Peut importe la manière dont on a défini les macros TRUE et FALSE, il suffit de faire if (x) pour tester si x est VRAI ... On utilise généralement ces macros pour initialiser une variable ou pour affecter une valeur, pas dans les expressions de test.

  4. #24
    Membre chevronné
    Profil pro
    Inscrit en
    Juillet 2007
    Messages
    309
    Détails du profil
    Informations personnelles :
    Âge : 39
    Localisation : France

    Informations forums :
    Inscription : Juillet 2007
    Messages : 309
    Par défaut
    Exactement, soyons cohérent... Quand on souhaite utiliser des booléens, il faut utiliser l'algèbre booléennes : !, &&, ||, le reste n'a pas vraiment de sens.

  5. #25
    Membre prolifique
    Avatar de Sve@r
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Février 2006
    Messages
    12 801
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Oise (Picardie)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : Aéronautique - Marine - Espace - Armement

    Informations forums :
    Inscription : Février 2006
    Messages : 12 801
    Billets dans le blog
    1
    Par défaut
    Citation Envoyé par Melem Voir le message
    D'ailleurs l'objectif c'est de pouvoir écrire du code compact (et rapide)
    Au débuts du C c'est ce que croyaient les programmeurs. A savoir que plus le code était compact et plus il était rapide.
    Au fil du temps (et aussi avec l'optimisation des compilos), ils se sont rendus compte qu'un code compact n'était pas forcément plus rapide qu'un code moins compact. La rapidité d'un code se joue surtout sur
    - éviter autant que possible x->y->z et préférer à la place stocker x->y dans tmp puis utiliser tmp->z
    - éviter autant que possible tab[i] (surtout si on le répète plusieurs fois ou si "tab" stocke un tableau de structures) et préférer utiliser "<type*> tmp=tab" puis "*tmp" associé à "tmp++"
    Et d'autres règles que je connais moins (comme l'ordre des membres d'une structure, l'alignement d'une structure sur des tailles bien précises quand on veut en avoir beaucoup dans un tableau etc...)
    Mon Tutoriel sur la programmation «Python»
    Mon Tutoriel sur la programmation «Shell»
    Sinon il y en a pleins d'autres. N'oubliez pas non plus les différentes faq disponibles sur ce site
    Et on poste ses codes entre balises [code] et [/code]

  6. #26
    Expert confirmé
    Avatar de Melem
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Janvier 2006
    Messages
    3 656
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 39
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : High Tech - Électronique et micro-électronique

    Informations forums :
    Inscription : Janvier 2006
    Messages : 3 656
    Par défaut
    Au débuts du C c'est ce que croyaient les programmeurs. A savoir que plus le code était compact et plus il était rapide.
    Au fil du temps (et aussi avec l'optimisation des compilos), ils se sont rendus compte qu'un code compact n'était pas forcément plus rapide qu'un code moins compact.
    Il n'était pas question de vitesse, il était question d'écriture. Comme je l'ai dit, notamment du fait de sa longueur, du code trop décompacté peut devenir illisble, donc il faut savoir faire un compromis. Le gain en vitesse peut avoir lieu, mais c'était un deuxième argument, que j'ai bien pris la peine de mettre entre parenthèses. Et pour terminer, vous ne voyez pas qu'on c'est déjà assez écarté du sujet comme ça?

  7. #27
    Membre prolifique
    Avatar de Sve@r
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Février 2006
    Messages
    12 801
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Oise (Picardie)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : Aéronautique - Marine - Espace - Armement

    Informations forums :
    Inscription : Février 2006
    Messages : 12 801
    Billets dans le blog
    1
    Par défaut
    Citation Envoyé par Melem Voir le message
    néanmoins je suis sûr (bien que j'ai pas compilé pour voir) que mon code est plus rapide que le tiens, c'est une certitude.
    Hé ben moi j'avais un peu de temps ce matin et j'ai compilé les deux codes suivants
    Code 1
    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
    void str_cpy(char * dest, char * src)
    {
    	while (*dest++ = *src++);
    }
     
    int main()
    {
    	char source[0x10000 + 1];
    	char dest[0x10000 + 1];
    	unsigned long i;
     
    	// Initialisation
    	for (i=0; i < 0x10000; i++)
    		source[i]='.';
    	source[i]=0;
     
    	// Copie
    	for (i=0; i < 10000; i++)
    		str_cpy(dest, source);
    	return 0;
    }
    Code 2
    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
    char * str_cpy(char *dest, char const *src)
    {
    	char *p_ret=0;
    	while (*src != 0)
    	{
    		*dest = *src;
    		dest++;
    		src++;
    	}
    	p_ret = dest;
     
    	return p_ret;
    }
     
    int main()
    {
    	char source[0x10000 + 1];
    	char dest[0x10000 + 1];
    	unsigned long i;
     
    	// Initialisation
    	for (i=0; i < 0x10000; i++)
    		source[i]='.';
    	source[i]=0;
     
    	// Copie
    	for (i=0; i < 10000; i++)
    		str_cpy(dest, source);
     
    	return 0;
    }
    J'ai lancé plusieurs fois l'un ou l'autre en les chronométrant sur un Linux récent (en utilisant le "time <nom pgm>". Et je les lançais parfois l'un en premier, parfois l'autre. Je les ai même lancés les deux en parallèle dans deux fenêtres différentes (ils ne démarraient qu'à la création d'un fichier que je créais depuis une 3° fenêtre pour bien qu'ils partent en même temps). Ben c'est toujours le code n° 2 qui était le plus rapide. Bon j'ai pas non plus fait 300 essais donc ma démo n'est pas non plus parfaite mais ça donne quand-même à réfléchir...

    Citation Envoyé par Melem Voir le message
    Et pour terminer, vous ne voyez pas qu'on c'est déjà assez écarté du sujet comme ça?
    Ah ? T'apprécies pas le plaisir de la discussion ???
    Mon Tutoriel sur la programmation «Python»
    Mon Tutoriel sur la programmation «Shell»
    Sinon il y en a pleins d'autres. N'oubliez pas non plus les différentes faq disponibles sur ce site
    Et on poste ses codes entre balises [code] et [/code]

  8. #28
    Expert confirmé
    Avatar de Melem
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Janvier 2006
    Messages
    3 656
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 39
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : High Tech - Électronique et micro-électronique

    Informations forums :
    Inscription : Janvier 2006
    Messages : 3 656
    Par défaut
    Citation Envoyé par Sve@r
    c'est toujours le code n° 2 qui était le plus rapide.
    T'es sur que t'as pas triché? . Je crois que moi aussi je devrais faire des tests, comme ça on pourra confronter nos résultats.

  9. #29
    Expert confirmé
    Avatar de Melem
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Janvier 2006
    Messages
    3 656
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 39
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : High Tech - Électronique et micro-électronique

    Informations forums :
    Inscription : Janvier 2006
    Messages : 3 656
    Par défaut
    Ben voilà, t'as bien triché! . Ta fonction ne copie pas le caractère de fin de chaîne (même remrque pour la fonction de Thierry). On avait tellement l'esprit ailleurs que personne ne l'a remarqué mais bref ... après la boucle tu dois encore ajouter le '\0', que tu n'a pas copié, ce qui fait une opération de plus, à moins de changer la boucle en do ... while et de boucler tant que *(src - 1) != '\0' et qui n'est finalement pas si lisible que ça, la preuve tout le monde s'est trompé ...

  10. #30
    Expert confirmé
    Avatar de Thierry Chappuis
    Homme Profil pro
    Enseignant Chercheur
    Inscrit en
    Mai 2005
    Messages
    3 499
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 48
    Localisation : Suisse

    Informations professionnelles :
    Activité : Enseignant Chercheur
    Secteur : Industrie Pharmaceutique

    Informations forums :
    Inscription : Mai 2005
    Messages : 3 499
    Par défaut
    Citation Envoyé par Melem Voir le message
    Ben voilà, t'as bien triché! . Ta fonction ne copie pas le caractère de fin de chaîne (même remrque pour la fonction de Thierry). On avait tellement l'esprit ailleurs que personne ne l'a remarqué mais bref ... après la boucle tu dois encore ajouter le '\0', que tu n'a pas copié, ce qui fait une opération de plus, à moins de changer la boucle en do ... while et de boucler tant que *(src - 1) != '\0' et qui n'est finalement pas si lisible que ça, la preuve tout le monde s'est trompé ...
    Il n'a pas triché, c'est une grosse erreur de ma part. Au temps pour moi. J'ai corrigé mon code ici: http://www.developpez.net/forums/sho...6&postcount=16

    Thierry
    "The most important thing in the kitchen is the waste paper basket and it needs to be centrally located.", Donald Knuth
    "If the only tool you have is a hammer, every problem looks like a nail.", probably Abraham Maslow

    FAQ-Python FAQ-C FAQ-C++

    +

  11. #31
    Expert confirmé
    Avatar de Melem
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Janvier 2006
    Messages
    3 656
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 39
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : High Tech - Électronique et micro-électronique

    Informations forums :
    Inscription : Janvier 2006
    Messages : 3 656
    Par défaut
    Citation Envoyé par Thierry Chappuis
    Citation Envoyé par Melem
    Ben voilà, t'as bien triché! . Ta fonction ne copie pas le caractère de fin de chaîne (même remrque pour la fonction de Thierry). On avait tellement l'esprit ailleurs que personne ne l'a remarqué mais bref ... après la boucle tu dois encore ajouter le '\0', que tu n'a pas copié, ce qui fait une opération de plus, à moins de changer la boucle en do ... while et de boucler tant que *(src - 1) != '\0' et qui n'est finalement pas si lisible que ça, la preuve tout le monde s'est trompé ...
    Il n'a pas triché, c'est une grosse erreur de ma part. Au temps pour moi.
    Mais bien sûûûû...ûr . Mais ca ne change rien à ma conclusion .

  12. #32
    Expert confirmé
    Avatar de Thierry Chappuis
    Homme Profil pro
    Enseignant Chercheur
    Inscrit en
    Mai 2005
    Messages
    3 499
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 48
    Localisation : Suisse

    Informations professionnelles :
    Activité : Enseignant Chercheur
    Secteur : Industrie Pharmaceutique

    Informations forums :
    Inscription : Mai 2005
    Messages : 3 499
    Par défaut
    Citation Envoyé par Melem Voir le message
    Mais bien sûûûû...ûr . Mais ca ne change rien à ma conclusion .
    Ca prouve juste que personne n'a relu ma fonction, y compris moi. J'admets que cette erreur grave ne parle pas en faveur de mon implantation.

    Thierry
    "The most important thing in the kitchen is the waste paper basket and it needs to be centrally located.", Donald Knuth
    "If the only tool you have is a hammer, every problem looks like a nail.", probably Abraham Maslow

    FAQ-Python FAQ-C FAQ-C++

    +

  13. #33
    Membre prolifique
    Avatar de Sve@r
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Février 2006
    Messages
    12 801
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Oise (Picardie)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : Aéronautique - Marine - Espace - Armement

    Informations forums :
    Inscription : Février 2006
    Messages : 12 801
    Billets dans le blog
    1
    Par défaut
    Citation Envoyé par Melem Voir le message
    Ben voilà, t'as bien triché! . Ta fonction ne copie pas le caractère de fin de chaîne (même remrque pour la fonction de Thierry). On avait tellement l'esprit ailleurs que personne ne l'a remarqué mais bref ... après la boucle tu dois encore ajouter le '\0', que tu n'a pas copié, ce qui fait une opération de plus, à moins de changer la boucle en do ... while et de boucler tant que *(src - 1) != '\0' et qui n'est finalement pas si lisible que ça, la preuve tout le monde s'est trompé ...
    Exact. Les tests ne sont pas bons
    C'est vrai que ça m'étonnait aussi car je m'attendais à avoir tantôt l'un tantôt l'autre (en fonction de la charge machine, de l'ordre de lancement, etc...)...
    Mon Tutoriel sur la programmation «Python»
    Mon Tutoriel sur la programmation «Shell»
    Sinon il y en a pleins d'autres. N'oubliez pas non plus les différentes faq disponibles sur ce site
    Et on poste ses codes entre balises [code] et [/code]

  14. #34
    Membre chevronné Avatar de Pierre Maurette
    Profil pro
    Inscrit en
    Juillet 2002
    Messages
    283
    Détails du profil
    Informations personnelles :
    Âge : 69
    Localisation : France

    Informations forums :
    Inscription : Juillet 2002
    Messages : 283
    Par défaut
    Je reviens un peu sur cette fameuse fonction à optimiser ou à ne pas optimiser.

    - Si la fonction est déclarée et documentée dans son .h, en bref si elle n'est pas static pour les quelques (voire une seule) fonctions qui l'utilisent, il est normal de la sécuriser un minimum dans la tradition de C. A moins éventuellement d'en faire une unsafe_str_cpy(), par exemple.
    A noter que la sécurisation en C ne peut pas aller bien loin. Pour ce genre de pointeur on peut juste vérifier qu'il n'est pas à NULL. Donc en gros considérer que le programmeur utilisateur sera assez "tête en l'air" pour ne se conformer à la documentation de la fonction, voire à l'évidence, et assez rigoureux (ou ses outils) pour être certain que tout pointeur non autrement initialisé ou libéré sera à NULL. On va donc très certainement avoir une foultitude de tests de pointeurs à NULL, redondants, mais si c'était un vrai problème, ça se saurait.
    Un petit truc me chagrine quand même: le retour char*. On connaît l'utilité de renvoyer un paramètre pointeur non constant, dans l'écriture plus naturelle du code qu'elle autorise, dans strcat() par exemple. Mais ici, le fait de mettre le retour à NULL quand src OU dest est à NULL rend le machin difficile à utiliser. Ou alors quelque chose m'échappe. Peut-être pourrait-on envisager une enum
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    enum STR_CPY_RETURN {
        STR_CPY_SUCESS = 0,
        STR_CPY_DSTBAD = 1,
        STR_CPY_SRCBAD = 2
    };
    ou autre, dans laquelle on peut lire la cause de l'erreur par masquage.

    - Pour ce qui est de l'optimisation, il faut avant tout qu'elle ait un sens. C'est à dire que les nanosecondes gagnées dans le test à NULL soient visibles dans le contexte.
    Nota: à mon avis, du code "bêtement trop lent" est le plus souvent "bête" avant d'être "trop lent".
    Ici le contexte pourrait être un ou des tableaux de char*, correctement initialisés à des tailles suffisantes. Ensuite, des centaines ou plus de copies de chaînes, parce qu'on a une bonne raison de swapper les chaînes et non les pointeurs. Plus les chaînes seront nombreuses et courtes, plus l'optimisation se fera sentir.
    C'est là qu'on sera tenté par
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    void str_cpy(char * dest, char * src)
    {
        while (*dest++ = *src++);
    }
    Mais ce sera déjà impérativement:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    static void str_cpy(char * dest, char * src)
    {
        while (*dest++ = *src++);
    }
    Mais à ce moment-là, l'appel de fonction, s'il n'est pas optimisé par le compilateur, deviendra plus coûteux qu'un test à NULL une fois dans la fonction. Autant le suggérer au compilateur, suggestion valant commentaire à la relecture du code:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    static inline void str_cpy(char * dest, char * src)
    {
        while (*dest++ = *src++);
    }
    Notez que pour faire taire un warning "mérité" et rendre votre code lisible, sans changer le code généré (quelques microsecondes de plus pour la compilation, vous devriez au moins faire:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    static inline void _str_cpy(char* dest, const char* src)
    {
        while ((*dest++ = *src++) != '\0');
    }
    Mais maintenant, à quoi sert la fonction par rapport à une macro, ou tout simplement un copié-collé du while() ? D'autant qu'alors ce code apparaîtrait directement dans le bloc où les pointeurs auront déjà été validés.

    Une voie d'optimisation serait, en fonction du contexte, de copier un nombre fixe de char, c'est à dire le plus souvent "un peu trop". Mais ça peut aller bien plus vite, dans certains cas, en particulier si ce nombre peut être connu avant la compilation. Et pourquoi pas multiple de sizeof(int).

  15. #35
    Membre chevronné
    Profil pro
    Inscrit en
    Juillet 2007
    Messages
    309
    Détails du profil
    Informations personnelles :
    Âge : 39
    Localisation : France

    Informations forums :
    Inscription : Juillet 2007
    Messages : 309
    Par défaut
    Je tiens à vous rappeler que selon le standard la fonction strcpy() retourne l'adresse du premier caractère de la chaîne de destination, et cette particularité est absente de toutes vos optimisations.

  16. #36
    Membre prolifique
    Avatar de Sve@r
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Février 2006
    Messages
    12 801
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Oise (Picardie)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : Aéronautique - Marine - Espace - Armement

    Informations forums :
    Inscription : Février 2006
    Messages : 12 801
    Billets dans le blog
    1
    Par défaut
    Citation Envoyé par Pierre Maurette Voir le message
    Je reviens un peu sur cette fameuse fonction à optimiser ou à ne pas optimiser.

    - Si la fonction est déclarée et documentée dans son .h, en bref si elle n'est pas static pour les quelques (voire une seule) fonctions qui l'utilisent, il est normal de la sécuriser un minimum dans la tradition de C. A moins éventuellement d'en faire une unsafe_str_cpy(), par exemple.
    A noter que la sécurisation en C ne peut pas aller bien loin. Pour ce genre de pointeur on peut juste vérifier qu'il n'est pas à NULL. Donc en gros considérer que le programmeur utilisateur sera assez "tête en l'air" pour ne se conformer à la documentation de la fonction, voire à l'évidence, et assez rigoureux (ou ses outils) pour être certain que tout pointeur non autrement initialisé ou libéré sera à NULL. On va donc très certainement avoir une foultitude de tests de pointeurs à NULL, redondants, mais si c'était un vrai problème, ça se saurait.
    Un petit truc me chagrine quand même: le retour char*. On connaît l'utilité de renvoyer un paramètre pointeur non constant, dans l'écriture plus naturelle du code qu'elle autorise, dans strcat() par exemple. Mais ici, le fait de mettre le retour à NULL quand src OU dest est à NULL rend le machin difficile à utiliser. Ou alors quelque chose m'échappe. Peut-être pourrait-on envisager une enum
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    enum STR_CPY_RETURN {
        STR_CPY_SUCESS = 0,
        STR_CPY_DSTBAD = 1,
        STR_CPY_SRCBAD = 2
    };
    ou autre, dans laquelle on peut lire la cause de l'erreur par masquage.

    - Pour ce qui est de l'optimisation, il faut avant tout qu'elle ait un sens. C'est à dire que les nanosecondes gagnées dans le test à NULL soient visibles dans le contexte.
    Nota: à mon avis, du code "bêtement trop lent" est le plus souvent "bête" avant d'être "trop lent".
    Ici le contexte pourrait être un ou des tableaux de char*, correctement initialisés à des tailles suffisantes. Ensuite, des centaines ou plus de copies de chaînes, parce qu'on a une bonne raison de swapper les chaînes et non les pointeurs. Plus les chaînes seront nombreuses et courtes, plus l'optimisation se fera sentir.
    C'est là qu'on sera tenté par
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    void str_cpy(char * dest, char * src)
    {
        while (*dest++ = *src++);
    }
    Mais ce sera déjà impérativement:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    static void str_cpy(char * dest, char * src)
    {
        while (*dest++ = *src++);
    }
    Mais à ce moment-là, l'appel de fonction, s'il n'est pas optimisé par le compilateur, deviendra plus coûteux qu'un test à NULL une fois dans la fonction. Autant le suggérer au compilateur, suggestion valant commentaire à la relecture du code:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    static inline void str_cpy(char * dest, char * src)
    {
        while (*dest++ = *src++);
    }
    Notez que pour faire taire un warning "mérité" et rendre votre code lisible, sans changer le code généré (quelques microsecondes de plus pour la compilation, vous devriez au moins faire:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    static inline void _str_cpy(char* dest, const char* src)
    {
        while ((*dest++ = *src++) != '\0');
    }
    Mais maintenant, à quoi sert la fonction par rapport à une macro, ou tout simplement un copié-collé du while() ? D'autant qu'alors ce code apparaîtrait directement dans le bloc où les pointeurs auront déjà été validés.

    Une voie d'optimisation serait, en fonction du contexte, de copier un nombre fixe de char, c'est à dire le plus souvent "un peu trop". Mais ça peut aller bien plus vite, dans certains cas, en particulier si ce nombre peut être connu avant la compilation. Et pourquoi pas multiple de sizeof(int).
    Plein d'éléments intéressants dans cette discussion. Je comprends pas trop pourquoi mettre la fonction en "static" (si on est dans un projet multisources ça va moins bien marcher) mais j'aime bien l'ensemble.

    Bon, je peux apporter quelques réponses
    1) pourquoi dédier la copie (une ligne) à une fonction plutôt que recopier la ligne dans le code => évolutivité. Aujourd'hui les strings C ont une caractéristique mais demain cela peut en être une autre. Une fonction = une modif. Alors que si on a copié la ligne dans le code...
    2) les remarques sur le contrôle inhérent avant d'entamer la copie sont excellentes. Rappelons que quand le C a été inventé, sa philosophie était "le programmeur sait ce qu'il fait". Si le programmeur passe un pointeur invalide à str_cpy() ben je vais pas pleurer sur son sort.

    Citation Envoyé par PsychoH13 Voir le message
    Je tiens à vous rappeler que selon le standard la fonction strcpy() retourne l'adresse du premier caractère de la chaîne de destination, et cette particularité est absente de toutes vos optimisations.
    Exact. Mais il s'agit d'une discussion plus dans un ton "général" à but lucratif qu'un projet à développer donc on peut passer ce détail qui n'enlève rien aux développements exposés...

    En revanche, ce qui m'inquiète, c'est que j'ai appris récemment que la simple présence d'une adresse invalide dans une variable de type "pointeur" invoquait un comportement indéterminé => http://www.developpez.net/forums/sho...=436475&page=2.
    Cela signifie que la boucle " while (*dest++ = *src++);" apporte un comportement indéterminé vu qu'en fin de boucle, "dest" et "src" ont dépassé l'espace de leur définition. J'aimerais bien qu'Emmanuel vienne jeter un oeuil sur ce débat et y apporter sa contrib car si mes conclusions sont correctes, cette fonction ne convient plus...
    Mon Tutoriel sur la programmation «Python»
    Mon Tutoriel sur la programmation «Shell»
    Sinon il y en a pleins d'autres. N'oubliez pas non plus les différentes faq disponibles sur ce site
    Et on poste ses codes entre balises [code] et [/code]

  17. #37
    Membre chevronné Avatar de Pierre Maurette
    Profil pro
    Inscrit en
    Juillet 2002
    Messages
    283
    Détails du profil
    Informations personnelles :
    Âge : 69
    Localisation : France

    Informations forums :
    Inscription : Juillet 2002
    Messages : 283
    Par défaut
    Citation Envoyé par Sve@r Voir le message
    Je comprends pas trop pourquoi mettre la fonction en "static" (si on est dans un projet multisources ça va moins bien marcher)
    Au contraire, non ?
    "static" ici ça signifie que la fonction ne sera visible que dans le module(*). En gros, j'ai choisi (erreur de ma part ?) que:

    - soit une fonction est utilisable hors du module, et je vais la déclarer et la documenter vers l'utilisateur dans le .h et la définir (et la documenter vers le programmeur) dans le .c.

    - soit elle est à pour la cuisine interne du module, elle n'a pas à être utilisée par d'autres modules, pire elle ne doit pas entrer en conflit avec une fonction de même nom définie à un endroit ou à un autre du projet, #include-s compris. Alors elle sera déclarée et définie en même temps dans le .c, avec "static" (rien ou "extern", c'est pareil). On peut dans ce cas séparer définition et déclaration pour des raisons de référence "forward", mais c'est marginal.

    Un exemple, qui montre aussi qu'on peut faire une fonction en "static inline" et y accéder de l'extérieur en même temps. Je pense qu'il y a dans mon code des précautions redondantes.
    main.c
    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
    #include <stdio.h>
    #include <stdlib.h>
     
    #include "pathkivabien\foo.h"
     
    static void debil(void) {
        puts("debil de main()");
    }
     
    int main(void) {
        debil();
        teste("Pierre");
        grosseFonction();
        grosMorceaudeGrosseFonction(); /* pour test ? */
        return (0);
    }
    foo.h
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    #ifndef FOO_H_
    #define FOO_H_
     
    void teste(const char* chaine);
    void grosseFonction(void);
    void grosMorceaudeGrosseFonction(void);
     
    #endif /*FOO_H_*/
    foo.c
    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
    #include <stdio.h>
     
    #include "pathkivabien\foo.h"
     
    static void debil(void);
    static inline void inline_grosMorceaudeGrosseFonction(void);
     
    void grosMorceaudeGrosseFonction(void) {
        /* tuyauterie selon besoin*/
        inline_grosMorceaudeGrosseFonction();
    }
     
    void grosseFonction() {
        /* du code */
        inline_grosMorceaudeGrosseFonction();
        /* du code */
    }
     
    void teste(const char* chaine) {
        debil();
        puts(chaine);
    }
     
    static inline void inline_grosMorceaudeGrosseFonction(void) {
        puts("inline_grosMorceaudeGrosseFonction");
    }
     
    static void debil(void) {
        puts("debil de foo()");
    }
    (*)j'utilise module, on peut lire "unité de compilation".

  18. #38
    Expert confirmé
    Avatar de diogene
    Homme Profil pro
    Enseignant Chercheur
    Inscrit en
    Juin 2005
    Messages
    5 761
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : Enseignant Chercheur
    Secteur : Enseignement

    Informations forums :
    Inscription : Juin 2005
    Messages : 5 761
    Par défaut
    Citation Envoyé par Sve@r Voir le message

    En revanche, ce qui m'inquiète, c'est que j'ai appris récemment que la simple présence d'une adresse invalide dans une variable de type "pointeur" invoquait un comportement indéterminé => http://www.developpez.net/forums/sho...=436475&page=2.
    Cela signifie que la boucle " while (*dest++ = *src++);" apporte un comportement indéterminé vu qu'en fin de boucle, "dest" et "src" ont dépassé l'espace de leur définition.
    La norme garantit que l'adresse qui suit la fin d'un objet est une adresse légale.

    n1124 :
    6.5.6 Additive operators
    8....
    Moreover, if the expression P points to the last element of an array object, the expression (P)+1 points one past the last element of the array object, and if the expression Q points one past the last element of an array object, the expression (Q)-1 points to the last element of the array object. If both the pointer operand and the result point to elements of the same array object, or one past the last element of the array object, the evaluation shall not produce an overflow; otherwise, the behavior is undefined. If the result points one past the last element of the array object, it shall not be used as the operand of a unary * operator that is evaluated.
    9....
    Moreover, if the expression P points either to an element of an array object or one past the last element of an array object, and the expression Q points to the last element of the same array object, the expression ((Q)+1)-(P) has the same value as ((Q)-(P))+1 and as -((P)-((Q)+1)), and has the value zero if the expression P points one past the last element of the array object, even though the expression (Q)+1 does not point to an element of the array object.89)

    89)....
    an implementation need only provide one extra byte (which may overlap another object in the program) just after the end of the object in order to satisfy the ‘‘one past the last element’’ requirements.

  19. #39
    Expert éminent
    Avatar de Emmanuel Delahaye
    Profil pro
    Retraité
    Inscrit en
    Décembre 2003
    Messages
    14 512
    Détails du profil
    Informations personnelles :
    Âge : 68
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Retraité

    Informations forums :
    Inscription : Décembre 2003
    Messages : 14 512
    Par défaut
    Citation Envoyé par diogene Voir le message
    La norme garantit que l'adresse qui suit la fin d'un objet est une adresse légale.
    Oui, et je l'avais d'ailleurs rappelé dans mon article :

    http://www.developpez.net/forums/sho...3&postcount=16

Discussions similaires

  1. utiliser les tag [MFC] [Win32] [.NET] [C++/CLI]
    Par hiko-seijuro dans le forum Visual C++
    Réponses: 8
    Dernier message: 08/06/2005, 15h57
  2. Réponses: 11
    Dernier message: 22/12/2003, 21h06
  3. Comment utiliser les styles XP avec Dev-C++?
    Par abraxas dans le forum Dev-C++
    Réponses: 3
    Dernier message: 05/10/2003, 19h47
  4. Merci d'utiliser les TAG
    Par Cian dans le forum Etudes
    Réponses: 0
    Dernier message: 07/08/2003, 17h46
  5. Utiliser les frames
    Par laury dans le forum Composants VCL
    Réponses: 5
    Dernier message: 10/05/2003, 10h14

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo