Où est la mise en œuvre de strlen() dans le GCC?

<!-Est-ce que quelqu'un peut m'indiquer la définition de <!-- En GCC? J'ai grappé la version 4.4.2 depuis environ une demi-heure maintenant (tout en Googlant comme un fou) et je n'arrive pas à trouver où strlen() est effectivement mis en œuvre.

18

10 réponses

Vous devriez chercher dans glibc, pas GCC -- il semble être défini dans strlen.c -- voici un lien vers strlen.c pour glibc version 2.7... Et voici un lien vers le glibc dépôt SVN en ligne pour strlen.c.

La raison pour laquelle vous devriez être à la recherche à glibc et pas gcc est:

la bibliothèque GNU C est utilisée comme bibliothèque C dans le système GNU et la plupart des systèmes avec Linux noyau.

29
répondu Mark Rushakoff 2009-11-14 04:42:46

je me rends compte que cette question Est vieille de 4 ans, mais gcc inclura souvent son copie de strlen si vous n'avez pas #include <string.h> et aucune des réponses (y compris la réponse acceptée) n'en tient compte. Si vous oubliez, vous obtiendrez un avertissement:

file_name:line_number: warning: incompatible implicit declaration of built-in function 'strlen'

et gcc inline sa copie qui sur x86 est la variante de repnz scasb asm à moins que vous ne passiez-Werror ou-FNO-builtin. Les fichiers liés à ce sont en gcc/config/<platform>/<platform>.{c,md}

Il est également contrôlé par gcc/les builtins.C. Dans le cas où vous vous demandiez si et comment un strlen() a été optimisé à une constante, voyez la fonction définie comme tree c_strlen(tree src, int only_value) dans ce fichier. Il contrôle également la façon dont strlen (entre autres) est étendu et plié (basé sur la config/plate-forme mentionnée précédemment)

10
répondu technosaurus 2013-11-10 03:18:32

Voici le bsd mise en oeuvre

size_t
strlen(const char *str)
{
        const char *s;

        for (s = str; *s; ++s)
                ;
        return (s - str);
}
7
répondu hyperlogic 2016-02-22 04:00:10

Est-ce ce que vous recherchez? strlen () source. Voir le git pour plus d'informations. glibc ressources page a des liens vers les dépôts git si vous voulez attraper plutôt que de regarder le vue web.

3
répondu faran 2009-11-14 04:39:55

bien que l'affiche originale ne le sache pas ou ne le cherche pas, gcc inline en interne un certain nombre de fonctions dites "builtin" c qu'il définit lui-même, y compris certaines des fonctions mem*() et (selon la version gcc) strlen. Dans de tels cas, la version de la bibliothèque n'est essentiellement jamais utilisée, et pointer la personne vers la version dans glibc n'est pas strictement correct. (Il le fait pour des raisons de performance-en plus de l'amélioration lui-même produit, gcc "sait" certaines choses sur les fonctions quand il les fournit, comme, par exemple, que strlen est une fonction pure et qu'il peut ainsi optimiser les appels multiples, ou dans le cas des fonctions mem*() qu'aucun aliasing n'a lieu.)

pour plus d'information, voir http://gcc.gnu.org/onlinedocs/gcc/Other-Builtins.html

3
répondu Perry 2012-02-18 03:15:28

Google Recherche De Code est un bon point de départ pour des questions comme ça. Ils pointent généralement vers diverses sources et implémentations différentes d'une fonction.

Dans votre cas particulier: GoogleCodeSearch (strlen)

Google Code Search a été complètement arrêté le mars 2013

3
répondu cschol 2016-09-27 06:29:53

définie dans glibc / string / strlen.c

#include <string.h>
#include <stdlib.h>

#undef strlen

#ifndef STRLEN
# define STRLEN strlen
#endif

/* Return the length of the null-terminated string STR.  Scan for
   the null terminator quickly by testing four bytes at a time.  */
size_t
STRLEN (const char *str)
{
  const char *char_ptr;
  const unsigned long int *longword_ptr;
  unsigned long int longword, himagic, lomagic;

  /* Handle the first few characters by reading one character at a time.
     Do this until CHAR_PTR is aligned on a longword boundary.  */
  for (char_ptr = str; ((unsigned long int) char_ptr
            & (sizeof (longword) - 1)) != 0;
       ++char_ptr)
    if (*char_ptr == '')
      return char_ptr - str;

  /* All these elucidatory comments refer to 4-byte longwords,
     but the theory applies equally well to 8-byte longwords.  */

  longword_ptr = (unsigned long int *) char_ptr;

  /* Bits 31, 24, 16, and 8 of this number are zero.  Call these bits
     the "holes."  Note that there is a hole just to the left of
     each byte, with an extra at the end:

     bits:  01111110 11111110 11111110 11111111
     bytes: AAAAAAAA BBBBBBBB CCCCCCCC DDDDDDDD

     The 1-bits make sure that carries propagate to the next 0-bit.
     The 0-bits provide holes for carries to fall into.  */
  himagic = 0x80808080L;
  lomagic = 0x01010101L;
  if (sizeof (longword) > 4)
    {
      /* 64-bit version of the magic.  */
      /* Do the shift in two steps to avoid a warning if long has 32 bits.  */
      himagic = ((himagic << 16) << 16) | himagic;
      lomagic = ((lomagic << 16) << 16) | lomagic;
    }
  if (sizeof (longword) > 8)
    abort ();

  /* Instead of the traditional loop which tests each character,
     we will test a longword at a time.  The tricky part is testing
     if *any of the four* bytes in the longword in question are zero.  */
  for (;;)
    {
      longword = *longword_ptr++;

      if (((longword - lomagic) & ~longword & himagic) != 0)
    {
      /* Which of the bytes was the zero?  If none of them were, it was
         a misfire; continue the search.  */

      const char *cp = (const char *) (longword_ptr - 1);

      if (cp[0] == 0)
        return cp - str;
      if (cp[1] == 0)
        return cp - str + 1;
      if (cp[2] == 0)
        return cp - str + 2;
      if (cp[3] == 0)
        return cp - str + 3;
      if (sizeof (longword) > 4)
        {
          if (cp[4] == 0)
        return cp - str + 4;
          if (cp[5] == 0)
        return cp - str + 5;
          if (cp[6] == 0)
        return cp - str + 6;
          if (cp[7] == 0)
        return cp - str + 7;
        }
    }
    }
}
libc_hidden_builtin_def (strlen)
2
répondu X Stylish 2018-04-25 16:03:24

je me rends compte que c'est une vieille question, vous pouvez trouver les sources du noyau linux à github ici, et l'implémentation 32 bits pour strlen () peut être trouvée dans strlen_32.c sur github. Le fichier mentionné a cette implémentation.

#include <linux/types.h>
#include <linux/string.h>
#include <linux/module.h>

size_t strlen(const char *s)
{
    /* Get an aligned pointer. */
    const uintptr_t s_int = (uintptr_t) s;
    const uint32_t *p = (const uint32_t *)(s_int & -4);

    /* Read the first word, but force bytes before the string to be nonzero.
     * This expression works because we know shift counts are taken mod 32.
     */
    uint32_t v = *p | ((1 << (s_int << 3)) - 1);

    uint32_t bits;
    while ((bits = __insn_seqb(v, 0)) == 0)
        v = *++p;

    return ((const char *)p) + (__insn_ctz(bits) >> 3) - s;
}
EXPORT_SYMBOL(strlen);
1
répondu A.B. 2016-09-28 08:05:11

Vous pouvez utiliser ce code, le plus simple le meilleur !

size_t Strlen ( const char * _str )
{
    size_t i = 0;
    while(_str[i++]);
    return i;
}
0
répondu Alisher Aliev 2018-02-24 20:38:21

glibc 2.26 a plusieurs implémentations d'assemblage optimisées à la main de strlen

glibc-2.26, un rapide:

git ls-files | grep strlen.S

dans l'arbre de glibc montre une douzaine d'implémentations d'assemblage optimisées à la main pour toutes les arches principales et les variations.

En particulier, x86_64 seul a 3 variations:

sysdeps/x86_64/multiarch/strlen-avx2.S
sysdeps/x86_64/multiarch/strlen-sse2.S
sysdeps/x86_64/strlen.S

un moyen rapide et sale pour déterminer lequel est utilisé, est de déboguer par étapes un test programme:

#include <assert.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>

int main(void) {
    size_t size = 0x80000000, i, result;
    char *s = malloc(size);
    for (i = 0; i < size; ++i)
        s[i] = 'a';
    s[size - 1] = '';
    result = strlen(s);
    assert(result == size - 1);
    return EXIT_SUCCESS;
}

compilé avec:

gcc -ggdb3 -std=c99 -O0 a.c

au Large de la chauve-souris:

disass main

contient:

callq  0x555555554590 <strlen@plt>

donc la version libc est appelée.

Après quelques si niveau de l'instruction des mesures dans le, GDB atteint:

__strlen_avx2 () at ../sysdeps/x86_64/multiarch/strlen-avx2.S:52                                         
52      ../sysdeps/x86_64/multiarch/strlen-avx2.S: No such file or directory.

ce qui me dit que strlen-avx2.S a été utilisé.

Ensuite, j'ai continué à confirmer avec:

disass __strlen_avx2

et comparer le démontage avec le glibc source.

il n'est pas surprenant que la version AVX2 ait été utilisée, puisque j'ai un i7-7820HQ CPU avec date de lancement Q1 2017 et support AVX2, et AVX2 est la plus avancée des implémentations d'assemblage, avec la date de lancement Q2 2013, alors que SSE2 est beaucoup plus ancien de 2004.

C'est d'ici qu'une grande partie de la dureté de glibc vient: il y a beaucoup d'assemblage écrit à la main optimisé à l'Arc code.

testé dans Ubuntu 17.10, gcc 7.2.0, glibc 2.26.

-O3

TODO: with -O3, gcc n'utilise pas les strlen, il génère juste l'assemblage inline, qui est mentionné à: https://stackoverflow.com/a/19885891/895245

Est-ce qu'elle peut optimiser encore mieux? Mais sa sortie ne contient pas d'instructions AVX2, donc je pense que ce n'est pas le cas.

https://www.gnu.org/software/gcc/projects/optimize.html mentions:

Lacunes de la GCC de l'optimiseur

glibc a des versions assembleur en ligne de diverses fonctions de chaîne; GCC en a quelques-unes, mais pas nécessairement les mêmes sur les mêmes architectures. Des entrées optab supplémentaires, comme celles pour ffs et strlen, pourraient être fournies pour plusieurs autres fonctions dont memset, strchr, strcpy et strrchr.

mes tests simples montrent que le -O3 la version est en fait plus rapide, donc GCC a fait le bon choix.

demandé à: https://www.quora.com/unanswered/How-does-GCC-know-that-its-builtin-implementation-of-strlen-is-faster-than-glibcs-when-using-optimization-level-O3

0