أين هو تنفيذ Strlen () في دول مجلس التعاون الخليجي؟

StackOverflow https://stackoverflow.com/questions/1733281

  •  20-09-2019
  •  | 
  •  

سؤال

هل يمكن لأي شخص أن يوضح لي تعريف strlen() في دول مجلس التعاون الخليجي؟ لقد كنت صديرا الإصدار 4.4.2 لمدة نصف ساعة تقريبا (في حين أن googling مثل مجنون) ولا أستطيع أن أجد أين strlen() يتم تنفيذها بالفعل.

هل كانت مفيدة؟

المحلول

يجب أن تبحث في Glibc، وليس خليجيا - يبدو أنه يعرف في strlen.c - إليك رابط strlen.c for glibc الإصدار 2.7... وهنا رابط إلى Glibc SVN مستودع عبر الإنترنت ل Strlen.c.

السبب يجب أن تبحث في glibc. وليس دول مجلس التعاون الخليجي هو:

يتم استخدام مكتبة جنو ج ال مكتبة ج في نظام جنو ومعظم النظم مع نواة لينكس.

نصائح أخرى

أدرك أن هذا السؤال قديم 4 سنوات، ولكن غالبا ما تشمل دول مجلس التعاون الخليجي ملك نسخة من strlen إذا كنت لا #include <string.h> وليس أي من الإجابات (بما في ذلك الإجابة المقبولة) حساب ذلك. إذا نسيت، فستحصل على تحذير:

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

وستنظير دول مجلس التعاون الخليجي نسختها التي تعمل على x86 البديل REPNZ SCASB ASM إلا إذا قمت باستمرار -Werror أو -fno الملفات المتعلقة بهذا في gcc/config/<platform>/<platform>.{c,md}

يتم التحكم فيه أيضا من قبل دول مجلس التعاون الخليجي / المدمج. في حال تستجيبت إذا تم تحسين وكيف تم تحسين Strlen () ثابتا، راجع الوظيفة المعرفة كما tree c_strlen(tree src, int only_value) في هذا الملف. كما أنه يتحكم في كيفية توسيع Strlen (من بين آخرين) ومطوية (بناء على التكوين / النظام الأساسي المذكور سابقا)

هنا BSD. التنفيذ

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

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

المعرفة في 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)

هل هذا ما كنت تبحث عنه؟ strlen () المصدر. وبعد انظر مستودع جيت للمزيد من المعلومات. ال Flibc Resources Page. يحتوي على روابط إلى مستودعات GIT إذا كنت ترغب في الاستيلاء عليها بدلا من النظر إلى طريقة عرض الويب.

على الرغم من أن الملصق الأصلي قد لا يعرف هذا أو كنت تبحث عن هذا، يدخل دول مجلس التعاون الخليجي داخليا عددا من الوظائف التي يسمى "المدمجة" التي تعرفها بمفردها، بما في ذلك بعض وظائف MEM * () و (اعتمادا على نسخة خليجية) strlen. في مثل هذه الحالات، يتم استخدام إصدار المكتبة بشكل أساسي، وإشارة الشخص الموجود في الإصدار في Glibc ليس صحيحا بدقة صحيح. (يفعل ذلك لأسباب الأداء - بالإضافة إلى التحسن الذي ينتج نفسه ينتج أيضا، يعرف دول مجلس التعاون الخليجي بعض الأشياء حول الوظائف عند توفرها، مثل، على سبيل المثال، أن Strlen هي وظيفة نقية وأنه يمكن بالتالي قم بتحسين مكالمات متعددة، أو في حالة وظائف MEM * () التي لا توجد مستعمرة تحدث.)

لمزيد من المعلومات حول هذا، انظر http://gcc.gnu.org/onlinedocs/gcc/other-builtins.html.

البحث عن رمز Google هي نقطة انطلاق جيدة لأسئلة من هذا القبيل. وعادة ما يشيرون إلى مختلف المصادر المختلفة والتنفيذ لوظيفة.

في حالتك الخاصة: googlecodesearch (strlen)

تم إيقاف تشغيل بحث رمز Google بالكامل في مارس 2013

Glibc 2.26 لديه العديد من تطبيقات الجمعية الأمثل strlen

اعتبارا من glibc-2.26, ، سريع:

git ls-files | grep strlen.S

في شجرة Glibc تظهر عشرات من تطبيقات التجميع الأمثل المحمولة لجميع الأقسام والاختلافات الرئيسية.

على وجه الخصوص، X86_64 وحده يحتوي على 3 أشكال:

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

طريقة سريعة وقذرة لتحديد أي واحد يستخدم، هو خطوة تصحيح برنامج اختبار:

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

جمعت مع:

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

قبالة الخفافيش:

disass main

يحتوي على:

callq  0x555555554590 <strlen@plt>

لذلك يتم استدعاء النسخة LIBC.

بعد قليل si خطوات مستوى التعليمات في ذلك، يصل GDB إلى:

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

الذي يخبرني ذلك strlen-avx2.S كان مستعملا.

ثم، أؤكد مع:

disass __strlen_avx2

ومقارنة التفكيك مع مصدر Glibc.

ليس من المستغرب أن تم استخدام إصدار AVX2، لأنني لدي I7-7820HQ. وحدة المعالجة المركزية مع تاريخ الإطلاق Q1 2017 ودعم AVX2، و avx2. هو الأكثر تقدما في تطبيقات الجمعية، مع تاريخ الإطلاق Q2 2013، في حين SSE2. هو أكثر قديمة من عام 2004.

هذا هو المكان الذي يأتي فيه جزء كبير من تصويت Glibc من: إنه يحتوي على الكثير من رمز التجميع المحسن من القوس المحسن.

تم اختباره في Ubuntu 17.10، GCC 7.2.0، Glibc 2.26.

-O3

علاقة -O3, ، لا يستخدم دول مجلس التعاون الخليجي glibc strlen, ، إنه يولد مجرد جمعية مضمنة، والتي ذكرت في: https://stackoverflow.com/a/19885891/895245.

هل ذلك لأنه يمكن تحسينه بشكل أفضل؟ لكن إنتاجه لا يحتوي على تعليمات AVX2، لذلك أشعر أن هذا ليس هو الحال.

https://www.gnu.org/software/gcc/projects/optimize.html. يذكر:

أوجه القصور في محسن دول مجلس التعاون الخليجي

يحتوي Glibc على إصدارات مجمع مضمنة من وظائف السلسلة المختلفة؛ لدى دول مجلس التعاون الخليجي بعض، ولكن ليس بالضرورة نفسها في نفس الهندسة. يمكن توفير إدخالات Optab الإضافية، مثل تلك الخاصة ب FFS و Strlen، لعدة مهام أكثر بما في ذلك Memets، Strchr، Strcpy و Strrchr.

اختباراتي البسيطة تظهر أن -O3 الإصدار هو في الواقع أسرع، لذلك جعلت دول مجلس التعاون الخليجي الاختيار الصحيح.

طلب في: https://www.quora.com/unanswered/how-does-gcc-know-that-its-builtin-Implementation-of-strlen-is-faster-than-glibcs-when-using-optimization-level-o3.

أدرك أن هذا سؤال قديم، يمكنك العثور على مصادر نواة Linux في Github هنا, ، ويمكن العثور على تطبيق 32 بت ل Strlen () في strlen_32.c. على جيثب. الملف المذكور لديه هذا التنفيذ.

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

يمكنك استخدام هذا الرمز، أبسط الأفضل!

size_t Strlen ( const char * _str )
{
    size_t i = 0;
    while(_str[i++]);
    return i;
}
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top