Frage

Kann mir jemand Punkt mich auf die Definition von strlen() in GCC? Ich habe jetzt greppen Release 4.4.2 für etwa eine halbe Stunde (während googeln wie verrückt) und ich kann nicht scheinen zu finden, wo strlen() tatsächlich umgesetzt wird.

War es hilfreich?

Lösung

Sie sollten in glibc suchen werden, nicht GCC - es scheint, in strlen.c definiert werden - hier ist ein Link auf strlen.c für glibc Version 2.7 ... Und hier ist ein Link auf die glibc SVN-Repository online strlen.c .

Der Grund, warum Sie unter glibc suchen sollten und nicht gcc ist:

  

Die GNU-C-Bibliothek verwendet wird, wie die C-Bibliothek in dem GNU-System und die meisten Systeme mit dem Linux-Kernel.

Andere Tipps

Ich weiß, diese Frage 4yrs alt, aber gcc wird oft auch sein eigene Kopieren von strlen wenn Sie nicht #include <string.h> und keine der Antworten (einschließlich der akzeptierten Antwort) Rechnung dafür. Wenn Sie vergessen haben, erhalten Sie eine Warnung erhalten:

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

und gcc wird seine Kopie inline, die auf x86 ist die repnz scasb asm Variante, wenn Sie Werror oder -fno-builtin passieren. Die Dateien im Zusammenhang mit dieser sind in gcc/config/<platform>/<platform>.{c,md}

Es wird auch von gcc / builtins.c gesteuert. Im Fall gefragt, ob und wie ein strlen () auf einen konstanten optimiert wurde, die Funktion als tree c_strlen(tree src, int only_value) in dieser Datei definiert sehen. Es steuert auch, wie strlen (ua) erweitert wird und gefaltet (basierend auf der zuvor erwähnten config / Plattform)

Hier ist der bsd Implementierung

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

        for (s = str; *s; ++s)
                ;
        return (s - str);
}

definiert in 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 == '\0')
      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)

Ist das, was Sie suchen? Strlen () Quelle . Siehe git-Repository für weitere Informationen. Die glibc Ressourcen hat Links zu den git Repositories, wenn man sie greifen wollen und nicht auf der Web-Ansicht an.

Obwohl das ursprüngliche Plakat nicht gekannt hat oder für diesen sucht, intern gcc inlines eine Reihe von sogenannten „builtin“ c-Funktionen, dass es auf seinem eigenen definiert, einige der mem * einschließlich () Funktionen und ( je nach gcc-Version) strlen. In solchen Fällen wird die Version der Bibliothek im Wesentlichen nie benutzt, und bei der Version in glibc die Person zeigt spricht nicht streng richtig. (Er tut dies aus Leistungsgründen - neben der Verbesserung, dass inlining selbst produziert, gcc „weiß“, bestimmte Dinge über die Funktionen, wenn es bietet ihnen, wie zum Beispiel, dass Strlen ist eine reine Funktion und es kann somit optimize weg mehrere Anrufe, oder im Fall der mem * () Funktionen, dass kein Aliasing stattfindet.)

Weitere Informationen hierzu finden Sie unter http://gcc.gnu.org /onlinedocs/gcc/Other-Builtins.html

Google Code Search ein guter Ausgangspunkt ist für Fragen wie diese. Sie weisen in der Regel auf verschiedene Quellen und Implementierungen einer Funktion.

In Ihrem speziellen Fall: GoogleCodeSearch (strlen)

Google Code Search vollständig wurde am März 2013 stillgelegt

glibc 2.26 hat mehrere Hand optimierte Montage Implementierungen von strlen

Ab glibc-2.26, ein schnell:

git ls-files | grep strlen.S

in der glibc Baum zeigt ein Dutzend von Montagehand optimierte Implementierungen für alle wichtigen Archs und Variationen.

Insbesondere x86_64 allein hat drei Varianten:

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

Eine schnelle und schmutzige Art und Weise zu bestimmen, welche verwendet wird, ist zu Schritt debug ein Testprogramm:

#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] = '\0';
    result = strlen(s);
    assert(result == size - 1);
    return EXIT_SUCCESS;
}

kompiliert mit:

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

Aus der Fledermaus:

disass main

enthält:

callq  0x555555554590 <strlen@plt>

so die libc-Version aufgerufen wird.

Nach einigen si Befehlsebene Schritten in dem, GDB erreicht:

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

, die mir sagt, dass strlen-avx2.S verwendet wurde,

Dann habe ich weiter mit bestätigen:

disass __strlen_avx2

und vergleichen Sie die Demontage mit der glibc Quelle.

Es ist nicht verwunderlich, dass die AVX2 Version verwendet wurde, da ich eine i7-7820HQ CPU mit Starttermin Q1 2017 und AVX2 Unterstützung und AVX2 die fortschrittlichste der Montage Implementierungen ist, mit Starttermin Q2 2013, während SSE2 von 2004 viel älter ist.

Dies ist, wo ein großer Teil der hardcoreness von glibc kommt aus:. Es viel Bogen optimiert Hand geschrieben Assembler-Code hat

Getestet in Ubuntu 17.10, gcc 7.2.0, glibc 2.26.

-O3

TODO: mit -O3, gcc nicht glibc nicht verwendet die strlen, es erzeugt nur Inline-Assembler, die an erwähnt wird: https: // stackoverflow.com/a/19885891/895245

Ist es, weil es noch besser optimieren können? Aber seine Ausgabe enthält keine AVX2 Anweisungen, so dass ich das Gefühl, dass dies nicht der Fall ist.

https://www.gnu.org/software/gcc/projects /optimize.html erwähnt:

  

Ein Mangel an GCC-Optimierer

     

glibc hat Inline-Assembler-Versionen von verschiedenen String-Funktionen; GCC hat einige, aber nicht unbedingt die gleichen, die auf den gleichen Architekturen. Zusätzliche optab Einträge, wie die, die für ffs und strlen, könnte für einige weitere Funktionen, einschließlich Memset, strchr, strcpy und strrchr zur Verfügung gestellt werden.

zeigen Meine einfachen Tests, dass die -O3 Version schneller ist eigentlich, so GCC die richtige Wahl getroffen.

Frage an: https://www.quora.com/unanswered/How-does-GCC-know-that-its-builtin-implementation-of-strlen- ist-schneller-als-glibcs-wenn-mit-Optimierung-Level-O3

Ich weiß, dass dies alte Frage, können Sie die Linux-Kernel-Quellen auf Github finden hier und die 32-Bit-Implementierung für strlen () könnte in strlen_32 finden .c auf gitHub. Die genannte Datei hat diese Implementierung.

#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);

Sie können diesen Code verwenden, desto einfacher, desto besser!

size_t Strlen ( const char * _str )
{
    size_t i = 0;
    while(_str[i++]);
    return i;
}
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top