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 :

strcat


Sujet :

C

  1. #1
    Inactif  

    Homme Profil pro
    Ingénieur test de performance
    Inscrit en
    Décembre 2003
    Messages
    1 986
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 50
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Ingénieur test de performance
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Décembre 2003
    Messages : 1 986
    Par défaut strcat
    Je développe un logiciel qui doit manipuler des chaînes de caractères.

    Pour gérer les erreurs, j'ai écrit une version personnalisée de strcat. Ceci me permet de contrôler que les tableaux se terminent bien par '\0', et que le tableau qui est concaténé a suffisamment de place.

    Puis pour la version release, j'utilise strcat du C standard, lorsque bien sur je sais que mes initialisations et mes gestions de tableaux sont correctes.

    Mais par curiosité j'ai écrit des versions de strcat et j'ai comparé les vitesses d'exécution:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    void szcpy2(char* tab1, const char* tab2){
     
      tab1 += strlen(tab1);
     
      while(*tab2)
        *tab1++ = *tab2++;
     
      *tab1 = '\0';
    }

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    void szcpy1(char* tab1, const char* tab2, size_t iSize){
     
      tab1 += iSize;
     
      while(*tab2)
        *tab1++ = *tab2++;
     
      *tab1 = '\0';
    }
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    void szcpy(char* tab1, const char* tab2){
     
      while(*tab1)
        tab1++;
     
      while(*tab2)
        *tab1++ = *tab2++;
     
      *tab1 = '\0';
    }
    J'ai affiché les fonctions de la plus rapide à la moins rapide. Et bien à ma grande surprise il y a une différence significative avec la fonction strcat du C standard. Je me demande comment se fait-il que mes fonctions soient beaucoup plus lentes.

    Est-ce que strcat est écrit en assembleur? Ou alors mes codes sont-ils pourris?

  2. #2
    Inactif  

    Homme Profil pro
    Ingénieur test de performance
    Inscrit en
    Décembre 2003
    Messages
    1 986
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 50
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Ingénieur test de performance
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Décembre 2003
    Messages : 1 986
    Par défaut
    voici le code de strcat standard:

    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
    char * __cdecl strcat (
            char * dst,
            const char * src
            )
    {
            char * cp = dst;
     
            while( *cp )
                    cp++;                   /* find end of dst */
     
            while( *cp++ = *src++ ) ;       /* Copy src to end of dst */
     
            return( dst );                  /* return dst */
     
    }
    Même avec cette fonction ce n'est pas mieux:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    void szcat(char* tab1, const char* tab2){
     
      while(*tab1)
        tab1++;
     
      while(*tab1++ = *tab2++);
    }
     
    je ne mémorise pas le pointeur de départ et bien c'est moins rapide quand même!!!!

  3. #3
    Membre expérimenté
    Profil pro
    Enculeur de mouches
    Inscrit en
    Septembre 2003
    Messages
    133
    Détails du profil
    Informations personnelles :
    Localisation : France, Creuse (Limousin)

    Informations professionnelles :
    Activité : Enculeur de mouches

    Informations forums :
    Inscription : Septembre 2003
    Messages : 133
    Par défaut
    Effectivement...
    Ce qui me parraît louche chez toi c'est que szcpy1() est plus lent que szcpy2(), alors qu'on économise l'appel à strlen() Tu es sûr que tu ne le fait pas avant d'appeler la fonction?
    Comment mesure tu le temps d'éxecution ? (il faut faire attention à ne pas mesurer le temps passé hors du processus, i.e. temps système et autres tâches).

    Pour le reste c'est probablement une question d'optimisation du compilateur.
    Le fait d'utiliser une variable locale (cp) dans la version standard permet au compilo d'en faire une variable register, ce qui économise un accès mémoire à chaque pas (dax le cache proce est rapide mais pas plus qu'un registre).

  4. #4
    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 Re: strcat
    Citation Envoyé par moldavi
    Est-ce que strcat est écrit en assembleur? Ou alors mes codes sont-ils pourris?
    Pour faire des copies rapides, il faut utiliser memcpy()...

    D'autre part, les fonctions de la bibliothèque sont écrites dans n'importe quel langage, car la norme décrit le comportement et non l'implémentation (heureusement). C'est ce qui permet à chaque bibliothèque d'être optimisée pour chaque cible, alors que le langage reste identique et portable.

  5. #5
    Rédacteur

    Avatar de gege2061
    Femme Profil pro
    Administrateur de base de données
    Inscrit en
    Juin 2004
    Messages
    5 840
    Détails du profil
    Informations personnelles :
    Sexe : Femme
    Âge : 41
    Localisation : France

    Informations professionnelles :
    Activité : Administrateur de base de données

    Informations forums :
    Inscription : Juin 2004
    Messages : 5 840
    Par défaut Re: strcat
    Citation Envoyé par Emmanuel Delahaye
    Citation Envoyé par moldavi
    Est-ce que strcat est écrit en assembleur? Ou alors mes codes sont-ils pourris?
    Pour faire des copies rapides, il faut utiliser memcpy()...

    D'autre part, les fonctions de la bibliothèque sont écrites dans n'importe quel langage, car la norme décrit le comportement et non l'implémentation (heureusement). C'est ce qui permet à chaque bibliothèque d'être optimisée pour chaque cible, alors que le langage reste identique et portable.
    C'est d'ailleur étonant que sa ne soit pas en assembleur!

  6. #6
    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 Re: strcat
    Citation Envoyé par gege2061
    C'est d'ailleur étonant que sa ne soit pas en assembleur!
    Qu'en sais tu ? memcpy() est souvent une fonction inline qui est implémentée à coup de copies rapides par blocs... (du moins en x86...)

  7. #7
    Membre émérite
    Profil pro
    Inscrit en
    Octobre 2004
    Messages
    633
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Octobre 2004
    Messages : 633
    Par défaut
    Bonjour,

    Si tu utilises VC++:
    l'algorithme standard que tu donnes n'est pas celui utilisé par le compilateur, même si on le trouve dans strcat.c

    Regarde le source strcat.c, il y a dedans
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    #pragma function (strcpy, strcat)
    Ceci signifiant que strcpy et strcat sont des fonctions spéciales.
    (va voir l'aide de #pragma, option function).

    Il y a d'autres sources pour ces fonctions dans:
    C:\Program Files\Microsoft Visual Studio .NET 2003\Vc7\crt\src\intel\strcat.asm

    et même celles-là ne semblent pas être le code utilisé par le compilateur (au moins en mode release) : ces fonctions "spéciales" ne sont normalement pas fournies en source.

    De toute manière, j'ai regardé le code généré, c'est tellement optimisé (la fonction standard), qu'il ne faut pas trop espérer faire mieux, ou alors très difficilement.

  8. #8
    Inactif  

    Homme Profil pro
    Ingénieur test de performance
    Inscrit en
    Décembre 2003
    Messages
    1 986
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 50
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Ingénieur test de performance
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Décembre 2003
    Messages : 1 986
    Par défaut
    Je n'attendais pas autant de réponses

    Je pense que vous êtes tous dans le vrai. Effectivement, j'utilise visual c++.net et je compile à la norme C++. C'est la raison pour laquelle j'ai omis les inline dans mes fonctions.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    Comment mesure tu le temps d'éxecution ?
    Pour faire mes tests, j'ai utilisé queryperformancecounter avec des boucles de 10000 évaluations, mais pour 100 évaluations les résultats sont similaires. Même si windows est multitâche et même si les résultats ne sont pas précis, le fait d'utiliser une boucle et de faire la moyenne permet d'avoir un ordre d'idée sur les vitesses d'exécution, et de pouvoir dire que tel fonction s'exécute plus vite qu'une autre.

    Ce qui me parraît louche chez toi c'est que szcpy1() est plus lent que szcpy2()
    Effectivement, ce n'est pas vrai à chaque fois, mais dans l'ensemble oui.
    En fait j'utilise strlen dans l'appel de fonction à szcpy2()

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    szcpy1(tab1, tab2,  strlen(tab1));
    Je suis aussi surpris que toi.


    Le fait d'utiliser une variable locale (cp) dans la version standard permet au compilo d'en faire une variable register
    Très intéressant, je vais regardé ça de plus près.

    Pour faire des copies rapides, il faut utiliser memcpy()...
    Je pense que strcat utilise memcpy effectivement.

    Ceci signifiant que strcpy et strcat sont des fonctions spéciales.
    (va voir l'aide de #pragma, option function).
    Tu as raison et plus tard j'ai remarqué ces #pragma. Il y a le #pragma intrinsic avec des valeurs comme _enable et _disable qui indiquerai au système d'exploitation de ne pas faire de multitâche entre ces deux indicateurs. Je vais regarder ça de plus près.

    De toute manière, j'ai regardé le code généré, c'est tellement optimisé (la fonction standard), qu'il ne faut pas trop espérer faire mieux, ou alors très difficilement.
    Je suis entièrement d'accord avec toi. L'idée général pour moi était de redéfinir strcat pour pouvoir utiliser une version en debug et une autre version en release.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
     
    #ifdefine _DEBUG
      #define szcat szcat1
    #else
      #define szcat szcat2
    #endif
    Mais vu que strcat est plus optimisée que szcat j'ai dû feinté.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
     
    #ifdefine _DEBUG
      static char* strcat(char*, const char*);
    #endif
    J'aimerais faire la même chose avec l'opérateur new sans surcharge, mais je posterai dans le forum C++.
    [/code]

  9. #9
    Rédacteur

    Avatar de gege2061
    Femme Profil pro
    Administrateur de base de données
    Inscrit en
    Juin 2004
    Messages
    5 840
    Détails du profil
    Informations personnelles :
    Sexe : Femme
    Âge : 41
    Localisation : France

    Informations professionnelles :
    Activité : Administrateur de base de données

    Informations forums :
    Inscription : Juin 2004
    Messages : 5 840
    Par défaut Re: strcat
    Citation Envoyé par Emmanuel Delahaye
    Citation Envoyé par gege2061
    C'est d'ailleur étonant que sa ne soit pas en assembleur!
    Qu'en sais tu ? memcpy() est souvent une fonction inline qui est implémentée à coup de copies rapides par blocs... (du moins en x86...)
    voici le code de strcat standard:

    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
     
    char * __cdecl strcat (
            char * dst,
            const char * src
            )
    {
            char * cp = dst;
     
            while( *cp )
                    cp++;                   /* find end of dst */
     
            while( *cp++ = *src++ ) ;       /* Copy src to end of dst */
     
            return( dst );                  /* return dst */
     
    }
    quelque underscore et trois mot d'anglais dans une source et je pense que c'est tiré de la bibliothèque standard:
    voici le code de strcat standard

  10. #10
    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 Re: strcat
    Citation Envoyé par gege2061
    voici le code de strcat standard:
    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
     
    char * __cdecl strcat (
            char * dst,
            const char * src
            )
    {
            char * cp = dst;
     
            while( *cp )
                    cp++;                   /* find end of dst */
     
            while( *cp++ = *src++ ) ;       /* Copy src to end of dst */
     
            return( dst );                  /* return dst */
     
    }
    quelque underscore et trois mot d'anglais dans une source et je pense que c'est tiré de la bibliothèque standard:
    voici le code de strcat standard
    "La bibliothèque standard" ça n'existe pas, du moins du point de vue implémentation. Encore une fois, ce que tu nous montres est une implémentation parmi d'autres de strcat().

    Code Composer (pour Texas Instrument DSP TMS320C54) :
    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
     
    /*****************************************************************************/
    /* string.h   v3.83                                                         */
    /* Copyright (c) 1993-2002 Texas Instruments Incorporated                    */
    /*****************************************************************************/
    <...>
    #if defined(_INLINE) || defined(_STRCAT)
    _OPT_IDEFN char *strcat(char *string1, const char *string2)
    {
       char       *s1 = string1 - 1;
       const char *s2 = string2 - 1;
     
       while (*++s1);		     /* FIND END OF STRING   */
       s1--;  			     /* BACK UP OVER NULL    */
       while (*++s1 = *++s2);	     /* APPEND SECOND STRING */
       return string1;
    }
    #endif /* _INLINE || _STRCAT */

  11. #11
    Inactif  

    Homme Profil pro
    Ingénieur test de performance
    Inscrit en
    Décembre 2003
    Messages
    1 986
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 50
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Ingénieur test de performance
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Décembre 2003
    Messages : 1 986
    Par défaut
    Les normes et les standards c'est tellement compliqué, même pour ceux qui les définissent, que je ne fais pas toujours attention à ce que je dis.

    Je corrige:

    Voici comment strcat est implémentée avec mon compilateur:

    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
    char * __cdecl strcat ( 
            char * dst, 
            const char * src 
            ) 
    { 
            char * cp = dst; 
     
            while( *cp ) 
                    cp++;                   /* find end of dst */ 
     
            while( *cp++ = *src++ ) ;       /* Copy src to end of dst */ 
     
            return( dst );                  /* return dst */ 
     
    }

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. Insérer des retours chariot dans un strcat
    Par Death83 dans le forum MATLAB
    Réponses: 4
    Dernier message: 17/10/2006, 13h53
  2. Problème avec strcat
    Par Bahan dans le forum C
    Réponses: 5
    Dernier message: 22/05/2006, 14h08
  3. Probleme strcat et strcpy
    Par grincheux01 dans le forum C
    Réponses: 6
    Dernier message: 25/04/2006, 12h07
  4. usage strcat et strtok
    Par Nalido dans le forum C
    Réponses: 13
    Dernier message: 24/04/2006, 23h05
  5. Pb avec fonction strcat ?
    Par olivier857 dans le forum Réseau
    Réponses: 44
    Dernier message: 31/03/2006, 12h00

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