গিলিবির স্ট্রেন দ্রুত চালানোর জন্য এত জটিল হওয়া দরকার কেন?


286

আমি এখানেstrlen কোডটি সন্ধান করছিলাম এবং আমি ভাবছিলাম যে কোডটিতে ব্যবহৃত অপটিমাইজেশন সত্যিই প্রয়োজন? উদাহরণস্বরূপ, নীচের মতো কাজ সমানভাবে ভাল বা আরও ভাল হবে না কেন?

unsigned long strlen(char s[]) {
    unsigned long i;
    for (i = 0; s[i] != '\0'; i++)
        continue;
    return i;
}

সংকলকটির জন্য সর্বোত্তম কোডটি আরও ভাল এবং / অথবা সহজতর নয়?

strlenলিঙ্কটির পেছনের পৃষ্ঠার কোডটি এরকম দেখাচ্ছে:

/* Copyright (C) 1991, 1993, 1997, 2000, 2003 Free Software Foundation, Inc.
   This file is part of the GNU C Library.
   Written by Torbjorn Granlund (tege@sics.se),
   with help from Dan Sahlin (dan@sics.se);
   commentary by Jim Blandy (jimb@ai.mit.edu).

   The GNU C Library is free software; you can redistribute it and/or
   modify it under the terms of the GNU Lesser General Public
   License as published by the Free Software Foundation; either
   version 2.1 of the License, or (at your option) any later version.

   The GNU C Library is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
   Lesser General Public License for more details.

   You should have received a copy of the GNU Lesser General Public
   License along with the GNU C Library; if not, write to the Free
   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
   02111-1307 USA.  */

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

#undef strlen

/* 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 (str)
     const char *str;
{
  const char *char_ptr;
  const unsigned long int *longword_ptr;
  unsigned long int longword, magic_bits, 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.  */
  magic_bits = 0x7efefeffL;
  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.  */
      magic_bits = ((0x7efefefeL << 16) << 16) | 0xfefefeffL;
      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 (;;)
    {
      /* We tentatively exit the loop if adding MAGIC_BITS to
     LONGWORD fails to change any of the hole bits of LONGWORD.

     1) Is this safe?  Will it catch all the zero bytes?
     Suppose there is a byte with all zeros.  Any carry bits
     propagating from its left will fall into the hole at its
     least significant bit and stop.  Since there will be no
     carry from its most significant bit, the LSB of the
     byte to the left will be unchanged, and the zero will be
     detected.

     2) Is this worthwhile?  Will it ignore everything except
     zero bytes?  Suppose every byte of LONGWORD has a bit set
     somewhere.  There will be a carry into bit 8.  If bit 8
     is set, this will carry into bit 16.  If bit 8 is clear,
     one of bits 9-15 must be set, so there will be a carry
     into bit 16.  Similarly, there will be a carry into bit
     24.  If one of bits 24-30 is set, there will be a carry
     into bit 31, so all of the hole bits will be changed.

     The one misfire occurs when bits 24-30 are clear and bit
     31 is set; in this case, the hole at bit 31 is not
     changed.  If we had access to the processor carry flag,
     we could close this loophole by putting the fourth hole
     at bit 32!

     So it ignores everything except 128's, when they're aligned
     properly.  */

      longword = *longword_ptr++;

      if (
#if 0
      /* Add MAGIC_BITS to LONGWORD.  */
      (((longword + magic_bits)

        /* Set those bits that were unchanged by the addition.  */
        ^ ~longword)

       /* Look at only the hole bits.  If any of the hole bits
          are unchanged, most likely one of the bytes was a
          zero.  */
       & ~magic_bits)
#else
      ((longword - lomagic) & himagic)
#endif
      != 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
মন্তব্যগুলি বর্ধিত আলোচনার জন্য নয়; এই কথোপকথন চ্যাটে সরানো হয়েছে ।
স্যামুয়েল লিউ

18
ভবিষ্যতের রেফারেন্সের জন্য, জিএনইউ লিবিসি-র জন্য অফিশিয়াল সোর্স রিপোজিটরিটি < সোর্স.আর.আর্গ / গিট /?p=glibc.git > এ রয়েছে। < সোর্স.আর.অর্গ / গীত /?p=glibc.git ; a = blob ; f = string/… > প্রকৃতপক্ষে উপরের মত কোড প্রদর্শন করে; তবে, sysdepsপরিবর্তে ডিরেক্টরি থেকে একটি হাতে লিখিত সমাবেশ ভাষা প্রয়োগ করা হবে, বেশিরভাগ গ্লিবসি সমর্থিত আর্কিটেকচারে (সর্বাধিক ব্যবহৃত আর্কিটেকচার যার প্রতিস্থাপন নেই এটি এমআইপিএস)।
zwol

9
এটি প্রাথমিকভাবে মতামত ভিত্তিক হিসাবে বন্ধ করতে ভোট দেওয়া; "এক্সএক্সএক্সএক্সএক্সএক্সএক্সএক্সএক্স দরকার?" জনগণের মতের সাপেক্ষে।
এসএস অ্যান

2
@ জেএল 2210: গুড পয়েন্ট, শিরোনামটিতে প্রশ্নের স্পিরিট ক্যাপচারের জন্য শিরোনামটি স্থির করেছে যা শোনাচ্ছে না যে পারফরম্যান্সের দরকার আছে কিনা তা ভাবছে না, পারফরম্যান্স পেতে আমাদের কেন এই অপ্টিমাইজেশানগুলির প্রয়োজন ।
পিটার

9
@ জেএল 2210 এফডাব্লুআইডাব্লু, মূল শিরোনামটি "সি [এসিক!] তে এত জটিল কেন ছিল", এবং এটি "খুব বিস্তৃত" হিসাবে বন্ধ হয়ে যায়, আবার খোলা হয়, তারপরে "প্রাথমিকভাবে মতামত ভিত্তিক" হিসাবে বন্ধ হয়। আমি এটিকে ঠিক করার চেষ্টা করেছি ("আপনি আমার প্রশ্নটি ভেঙে দিয়েছিলেন!" এবং "এর মধ্যে আপনি আপনার সম্পাদনা শক্তিগুলিকে অপব্যবহার করছেন!") তবে প্রশ্নটির মূল ভিত্তিতে সমস্যাটি মিথ্যা বলেছে (এবং এখনও মিথ্যা), যা সমস্যাযুক্ত ছিল ("এই কোডটি আমার বুঝতে বোঝার পক্ষে জটিল") প্রশ্নোত্তরের জন্য খুব উপযুক্ত নয় - আইএমও এটি টিউটারিংয়ের জন্য একটি অনুরোধ, কোনও উত্তরের জন্য নয়)। আমি এটি 60-ফুটের মেরু দিয়ে আবার স্পর্শ করছি না :)

উত্তর:


233

আপনি না প্রয়োজন এবং আপনি কখনই উচিত যে ভালো লেখার কোড - বিশেষ করে যদি আপনি একটি সি কম্পাইলার / মান গ্রন্থাগার বিক্রেতা নন। এটি strlenকিছু খুব সন্দেহজনক গতির হ্যাক এবং অনুমানের সাথে প্রয়োগ করার কোড (যা দৃ (়তার সাথে পরীক্ষা করা হয় না বা মন্তব্যে উল্লিখিত হয় না):

  • unsigned long হয় 4 বা 8 বাইট হয়
  • বাইট 8 বিট হয়
  • একটি পয়েন্টার কাস্ট করা যেতে পারে unsigned long longএবং নাuintptr_t
  • 2 বা 3 সর্বনিম্ন অর্ডার বিট শূন্য কিনা তা পরীক্ষা করে কেউ পয়েন্টারটিকে সারিবদ্ধ করতে পারে
  • এক হিসাবে একটি স্ট্রিং অ্যাক্সেস করতে পারেন unsigned longগুলি
  • কোনওরকম খারাপ প্রভাব ছাড়াই অ্যারের শেষটি পড়া যায়।

আরও কি, একটি ভাল সংকলক এমনকি কোড লিখিত প্রতিস্থাপন করতে পারে

size_t stupid_strlen(const char s[]) {
    size_t i;
    for (i=0; s[i] != '\0'; i++)
        ;
    return i;
}

(লক্ষ্য করুন যে এটির সাথে এক ধরণের সামঞ্জস্যপূর্ণ হতে হবে size_t) সংকলক অন্তর্নির্মিত অন্তর্নিহিত সংস্করণ সহ strlen, বা কোডটি ভেক্টরাইজ করতে হবে; তবে একটি সংকলক জটিল সংস্করণটি অপ্টিমাইজ করতে সক্ষম হওয়ার সম্ভাবনা কম।


strlenফাংশন দ্বারা বর্ণনা করা হয়েছে C11 7.24.6.3 হিসাবে:

বিবরণ

  1. strlenফাংশন স্ট্রিং গুলি দ্বারা প্রতি ইঙ্গিত দৈর্ঘ্য নির্ণয় করে।

রিটার্নস

  1. strlenফাংশন অক্ষর আছে যা সসীম নাল চরিত্র আগে বসে সংখ্যার উল্লেখ করে।

এখন, যদি স্ট্রিংটি নির্দেশিত sস্ট্রিংটি স্ট্রিং এবং টার্মিনেটিং এনএলএলকে ধারণ করতে যথেষ্ট দীর্ঘ অক্ষরের অ্যারে থাকে তবে নাল টার্মিনেটরের পাশের স্ট্রিংটিতে অ্যাক্সেস করা থাকলে আচরণটি অনির্ধারিত হবে , উদাহরণস্বরূপ

char *str = "hello world";  // or
char array[] = "hello world";

সত্যিই তাই শুধুমাত্র সম্পূর্ণরূপে পোর্টেবল / মান পথ অনুবর্তী সি এই বাস্তবায়ন সঠিকভাবে উপায় এটা আপনার লেখা হয় প্রশ্ন তুচ্ছ রূপান্তরের ছাড়া, - আপনি লুপের ইত্যাদি unrolling দ্বারা দ্রুত হতে জাহির করতে পারেন, কিন্তু এটি এখনও সম্পন্ন করা প্রয়োজন এক সময় এক বাইট

(মন্তব্যকারীরা যেমন উল্লেখ করেছেন, যখন কঠোর বহনযোগ্যতা বোঝা খুব বেশি হয় তখন যুক্তিসঙ্গত বা জ্ঞাত-নিরাপদ অনুমানের সদ্ব্যবহার করা সবসময় খারাপ জিনিস হয় না। বিশেষত কোডে এটি একটি নির্দিষ্ট সি বাস্তবায়নের অংশ । তবে আপনাকে বুঝতে হবে কীভাবে / কখন আপনি এগুলি বাঁকতে পারেন তা জানার আগে নিয়ম করে))


লিঙ্কযুক্ত strlenবাস্তবায়ন প্রথমে স্বতন্ত্রভাবে বাইটগুলি পরীক্ষা করে অবধি পয়েন্টারটি প্রাকৃতিক 4 বা 8 বাইট প্রান্তিককরণের সীমানায় নির্দেশ না করা পর্যন্ত unsigned long। সি স্ট্যান্ডার্ড বলছে যে সঠিকভাবে প্রান্তিক নয় এমন পয়েন্টার অ্যাক্সেস করা অপরিজ্ঞাত আচরণ করে , সুতরাং পরবর্তী নোংরা কৌশলটি আরও ডাইরিয়ার হওয়ার জন্য এটি একেবারে করতে হবে। (কিছু সিপিইউ এক্স 86 ছাড়া অন্য আর্কিটেকচারের উপর বাস্তবে, একটি শ্রেণীবদ্ধ শব্দ বা doubleword লোড দোষ হবে না। সি না পোর্টেবল সমাবেশ ভাষা কিন্তু এই কোড এটা যে পথ ব্যবহার করছে)। এটি এমন কি যা বাস্তবায়নের ক্ষেত্রে দোষের ঝুঁকি ছাড়াই কোনও অবজেক্টের শেষে পড়া সম্ভব করে যেখানে মেমরি সুরক্ষা প্রান্তিকৃত ব্লকগুলিতে কাজ করে (যেমন 4kiB ভার্চুয়াল মেমরি পৃষ্ঠাগুলি)।

এখন নোংরা অংশটি আসে: কোডটি প্রতিশ্রুতি ভঙ্গ করে এবং একবারে (ক long int) 4 বা 8 8-বিট বাইট পড়ে এবং 4 বা 8 এর মধ্যে কোনও শূন্য বাইট রয়েছে কিনা তা খুঁজে বের করার জন্য স্বাক্ষরবিহীন সংযোজন সহ কিছুটা কৌশল ব্যবহার করে বাইটস - এটি একটি বিশেষভাবে তৈরি কারিগর সংখ্যার ব্যবহার করে যা ক্যারি বিটকে বিটকে মাস্ক দ্বারা ধরা পড়া বিট পরিবর্তন করতে পারে। সংক্ষেপে এটি তখন বুঝতে পারে যে যদি মুখোশের 4 বা 8 বাইটগুলির মধ্যে কোনওটি শূন্য হয় তবে এই প্রতিটি বাইটের মধ্য দিয়ে লুপিংয়ের চেয়ে সম্ভবত দ্রুত গতি সম্পন্ন হবে। অবশেষে এখানে একটি লুপ রয়েছে যা নির্ধারণ করতে হবে যে কোন বাইটটি প্রথম শূন্য ছিল, যদি কোনও হয়, এবং ফলাফলটি ফিরে আসে।

সবচেয়ে বড় সমস্যাটি হ'ল sizeof (unsigned long) - 1সময়ের বাইরে sizeof (unsigned long)এটি স্ট্রিংয়ের শেষটি পড়তে পারে - কেবল যদি নাল বাইটটি সর্বশেষ অ্যাক্সেস করা বাইটে থাকে (যেমন, লিড-এডিয়ানে সর্বাধিক তাৎপর্যপূর্ণ এবং বিগ-এন্ডিয়ানে অন্তত তাৎপর্যপূর্ণ) , এটি সীমা ছাড়িয়ে অ্যারে অ্যাক্সেস না !


কোডটি, যদিও strlenএকটি সি স্ট্যান্ডার্ড লাইব্রেরিতে প্রয়োগ করতে ব্যবহৃত হয় তা খারাপ কোড। এটিতে বেশ কয়েকটি বাস্তবায়ন-সংজ্ঞায়িত এবং অপরিজ্ঞাত দিক রয়েছে এবং এটি সিস্টেম-সরবরাহিত পরিবর্তে কোথাও ব্যবহার করা উচিত নয় strlen- আমি the_strlenএখানে ফাংশনটির নামকরণ করেছি এবং নিম্নলিখিতগুলি যুক্ত করেছি main:

int main(void) {
    char buf[12];
    printf("%zu\n", the_strlen(fgets(buf, 12, stdin)));
}

বাফারটি সাবধানতার সাথে আকারযুক্ত যাতে এটি hello worldস্ট্রিং এবং টার্মিনেটরটি ঠিক ধরে রাখতে পারে । তবে আমার 64৪-বিট প্রসেসরের unsigned longউপর 8 বাইট রয়েছে, সুতরাং উত্তরোত্তর অ্যাক্সেসটি এই বাফারকে ছাড়িয়ে যাবে।

আমি যদি এখন ফলাফলটি সংকলন করে -fsanitize=undefinedএবং -fsanitize=addressচালিত করি তবে আমি পেয়েছি:

% ./a.out
hello world
=================================================================
==8355==ERROR: AddressSanitizer: stack-buffer-overflow on address 0x7ffffe63a3f8 at pc 0x55fbec46ab6c bp 0x7ffffe63a350 sp 0x7ffffe63a340
READ of size 8 at 0x7ffffe63a3f8 thread T0
    #0 0x55fbec46ab6b in the_strlen (.../a.out+0x1b6b)
    #1 0x55fbec46b139 in main (.../a.out+0x2139)
    #2 0x7f4f0848fb96 in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x21b96)
    #3 0x55fbec46a949 in _start (.../a.out+0x1949)

Address 0x7ffffe63a3f8 is located in stack of thread T0 at offset 40 in frame
    #0 0x55fbec46b07c in main (.../a.out+0x207c)

  This frame has 1 object(s):
    [32, 44) 'buf' <== Memory access at offset 40 partially overflows this variable
HINT: this may be a false positive if your program uses some custom stack unwind mechanism or swapcontext
      (longjmp and C++ exceptions *are* supported)
SUMMARY: AddressSanitizer: stack-buffer-overflow (.../a.out+0x1b6b) in the_strlen
Shadow bytes around the buggy address:
  0x10007fcbf420: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x10007fcbf430: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x10007fcbf440: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x10007fcbf450: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x10007fcbf460: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
=>0x10007fcbf470: 00 00 00 00 00 00 00 00 00 00 f1 f1 f1 f1 00[04]
  0x10007fcbf480: f2 f2 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x10007fcbf490: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x10007fcbf4a0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x10007fcbf4b0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x10007fcbf4c0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
Shadow byte legend (one shadow byte represents 8 application bytes):
  Addressable:           00
  Partially addressable: 01 02 03 04 05 06 07 
  Heap left redzone:       fa
  Freed heap region:       fd
  Stack left redzone:      f1
  Stack mid redzone:       f2
  Stack right redzone:     f3
  Stack after return:      f5
  Stack use after scope:   f8
  Global redzone:          f9
  Global init order:       f6
  Poisoned by user:        f7
  Container overflow:      fc
  Array cookie:            ac
  Intra object redzone:    bb
  ASan internal:           fe
  Left alloca redzone:     ca
  Right alloca redzone:    cb
==8355==ABORTING

অর্থাত্ খারাপ ঘটনা ঘটেছে।


120
পুনরায়: "খুব প্রশ্নবিদ্ধ স্পিড হ্যাক এবং অনুমান" - এটি পোর্টেবল কোডে খুব প্রশ্নবিদ্ধ । স্ট্যান্ডার্ড লাইব্রেরিটি একটি নির্দিষ্ট সংকলক / হার্ডওয়্যার সংমিশ্রনের জন্য রচিত, ভাষার সংজ্ঞাটি অপরিজ্ঞাত হিসাবে রেখে যাওয়া জিনিসগুলির আসল আচরণ সম্পর্কে জ্ঞান সহ। হ্যাঁ, বেশিরভাগ লোকের মতো কোড লেখা উচিত নয়, তবে মানক গ্রন্থাগারটি অ-বহনযোগ্য প্রয়োগ করার প্রসঙ্গে সহজাত খারাপ নয়।
পিট বেকার

4
সম্মত হন, নিজের মতো জিনিস কখনই লিখবেন না। বা প্রায় কখনও না। অকালীন অপটিমাইজেশন হ'ল সমস্ত অশুভের উত্স। (এই ক্ষেত্রে এটি আসলে উত্সাহিত হতে পারে)। যদি আপনি একই খুব দীর্ঘ স্ট্রিংটিতে প্রচুর স্ট্রেন () কল করেন তবে আপনার আবেদনটি সম্ভবত অন্যভাবে লেখা যেতে পারে। আপনি উদাহরণস্বরূপ স্থান পরিবর্তন করেছেন যখন স্ট্রিংটি তৈরি হয় তখনই ভেরিয়েবলের মধ্যে স্ট্রিংলেেন্থ সংরক্ষণ করুন, এবং একেবারে স্ট্রেন () কল করার প্রয়োজন নেই।
ghellquist

65
@ গেলকুইস্ট: প্রায়শই ব্যবহৃত লাইব্রেরি কলকে অনুকূলকরণ করা খুব কমই "অকাল অপ্টিমাইজেশন"।
জামেএসকিফ

7
@ আন্টি হাপাল: ঠিক আপনি কেন মনে করেন স্ট্রেন ও (O) হওয়া উচিত? এবং আমাদের এখানে যা রয়েছে তা বেশ কয়েকটি বাস্তবায়ন, এর সবগুলি ও (এন), তবে বিভিন্ন ধ্রুবক গুণক সহ। আপনি এটি গুরুত্বপূর্ণ মনে করেন না, তবে আমাদের কারও কারও জন্য একটি ও (এন) অ্যালগরিদম বাস্তবায়ন যা মাইক্রোসেকেন্ডগুলিতে এটি কাজ করে যা সেকেন্ড, এমনকি মিলিসেকেন্ডের চেয়ে অনেক বেশি ভাল কারণ এটি কয়েক বিলিয়ন বার বলা যেতে পারে একটি কাজের অবশ্যই
জামেএসকিফ

8
@ পেটবেকার: কেবল এটিই নয়, স্ট্যান্ডার্ড লাইব্রেরির পরিপ্রেক্ষিতে (যদিও এই উদাহরণে এতটা নয়) ননপোর্টেবল কোড রচনা করা আদর্শ হতে পারে কারণ একটি স্ট্যান্ডার্ড লাইব্রেরির উদ্দেশ্য নির্দিষ্ট স্টাফগুলি বাস্তবায়নের জন্য একটি স্ট্যান্ডার্ড ইন্টারফেস সরবরাহ করা।
প্লাজমাএইচএইচ

148

এর জন্য কিছু বিবরণ / পটভূমি সম্পর্কে মন্তব্যগুলিতে অনেকগুলি (সামান্য বা সম্পূর্ণ) ভুল অনুমান হয়েছে।

আপনি গিলিবির অপ্টিমাইজড সি ফ্যালব্যাক অনুকূলিতকরণ বাস্তবায়নটির দিকে তাকিয়ে আছেন (আইএসএগুলির জন্য যাদের হাতে লিখিত asm বাস্তবায়ন নেই) । বা সেই কোডটির একটি পুরানো সংস্করণ, যা এখনও গ্লিবসি উত্স ট্রিতে রয়েছে। https://code.woboq.org/userspace/glibc/string/strlen.c.html একটি কোড ব্রাউজার যা বর্তমান গ্লিবসি গিট ট্রি উপর ভিত্তি করে। স্পষ্টতই এটি এখনও এমআইপিএস সহ কয়েকটি মূলধারার গ্লিবসি লক্ষ্যগুলি ব্যবহার করে। (ধন্যবাদ @ জেওল)

X86 এবং এআরএম এর মতো জনপ্রিয় আইএসএ-তে, গ্লিবসি হস্ত-লিখিত এসএমটি ব্যবহার করে

সুতরাং এই কোডটি সম্পর্কে যে কোনও কিছু পরিবর্তনের উত্সাহ আপনার ভাবার চেয়ে কম।

এই বিট্যাক কোডটি ( https://ographicics.stanford.edu/~seender/bithacks.html#ZeroInWord ) আসলে আপনার সার্ভার / ডেস্কটপ / ল্যাপটপ / স্মার্টফোনে চালিত নয়। এটি নিখরচায় বাইট-এ-এ-টাইম লুপের চেয়ে ভাল, তবে আধুনিক সিপিইউগুলির জন্য দক্ষ এসএমের তুলনায় এই বিটাকটি বেশ খারাপ (বিশেষত x86 যেখানে AVX2 সিমডি একটি ঘড়ি প্রতি 32 থেকে 64 বাইটের অনুমতি দিয়ে একটি দম্পতি নির্দেশনা দিয়ে 32 বাইট চেক করতে দেয় 2 / ঘড়ি ভেক্টর লোড এবং ALU থ্রুপুট সহ আধুনিক সিপিইউগুলিতে L1d ক্যাশে ডেটা গরম থাকলে প্রধান লুপটিতে চক্র ie অর্থাত্ মাঝারি আকারের স্ট্রিংগুলির জন্য যেখানে স্টার্টআপ ওভারহেড প্রাধান্য পায় না))

গ্লিবিসি strlenআপনার সিপিইউয়ের জন্য অনুকূল সংস্করণের সমাধানের জন্য ডায়নামিক লিঙ্কিং ট্রিকস ব্যবহার করে , তাই x86 এর মধ্যে একটি এসএসই 2 সংস্করণ (16-বাইট ভেক্টর, x86-64 এর বেসলাইন) এবং একটি এভিএক্স 2 সংস্করণ (32-বাইট ভেক্টর) রয়েছে।

x86 এর ভেক্টর এবং সাধারণ-উদ্দেশ্য রেজিস্টারগুলির মধ্যে দক্ষ ডেটা ট্রান্সফার রয়েছে, যা লুপ নিয়ন্ত্রণ ডেটা নির্ভরশীল যেখানে অন্তর্নিহিত দৈর্ঘ্যের স্ট্রিংগুলিতে সিমড ব্যবহারের জন্য এটি অনন্যভাবে (?) ভাল করে তোলে। pcmpeqb/ pmovmskbএকবারে 16 টি পৃথক বাইট পরীক্ষা করা সম্ভব করে তোলে।

গ্লিবির অ্যাডসআইএমডি ব্যবহার করে এর মতো একটি আআরচ version৪ সংস্করণ রয়েছে এবং এআরচ CP৪ সিপিইউগুলির একটি সংস্করণ যেখানে ভেক্টর-> জিপি রেজিস্টার পাইপলাইন স্টল করে, তাই এটি আসলে এই বিট্যাকটি ব্যবহার করে না । তবে একবার হিট হয়ে গেলে বাইট-ইন-রেজিস্টার সন্ধান করতে গণনা-শীর্ষস্থানীয়-জিরো ব্যবহার করে এবং পৃষ্ঠা-ক্রসিংয়ের জন্য যাচাইয়ের পরে এআরচ's৪ এর দক্ষ অ-স্বাক্ষরিত অ্যাক্সেসগুলির সুবিধা গ্রহণ করে।

এছাড়াও সম্পর্কিত: এই কোডটি 6.5x কেন অপ্টিমাইজেশান সহ ধীর? strlenবৃহত্তর বাফার সহ x86 এএসএম ধীরে ধীরে ধীরে ধীরে ধীরে ধীরে ধীরে ধীরে ধীরে ধীরে হ্রাস পেতে আরও কিছু বিশদ রয়েছে এবং একটি সাধারণ এএসএম বাস্তবায়ন যা কীভাবে ইনলাইন করতে হয় তা জিসিসির পক্ষে ভাল হতে পারে। (কিছু জিসিসি সংস্করণ অজ্ঞাতসারে ইনলাইন rep scasbযা খুব ধীর, বা 4-বাইট-এ-এ-টাইম বিট্যাক এর মতো So তাই জিসিসির ইনলাইন-স্ট্রলন রেসিপিটির আপডেট বা অক্ষম করা দরকার))

আসমের সি-স্টাইলের "অপরিজ্ঞাত আচরণ" নেই ; আপনার পছন্দ মতো মেমরির বাইটগুলি অ্যাক্সেস করা নিরাপদ এবং কোনও প্রান্তিক লোড যাতে কোনও বৈধ বাইট অন্তর্ভুক্ত করতে পারে তা দোষ দিতে পারে না। সারিবদ্ধ পৃষ্ঠাগুলি সহ স্মৃতি সুরক্ষা ঘটে; এর চেয়ে সংকীর্ণ অ্যাক্সেসগুলি পৃষ্ঠার সীমানা অতিক্রম করতে পারে না। X86 এবং x64 এ একই পৃষ্ঠার মধ্যে বাফারের শেষটি পড়া কি নিরাপদ? এই সি সি হ্যাকটি এই ফাংশনটির এককভাবে অ-ইনলাইন প্রয়োগের জন্য সংযোজকগণ তৈরি করে এমন মেশিন-কোডেও একই যুক্তি প্রযোজ্য।

যখন কোনও সংকলক অজানা নন-ইনলাইন ফাংশনটি কল করার জন্য কোডটি প্রেরণ করে, তখন ধরে নিতে হবে যে ফাংশনটি কোনও / সমস্ত গ্লোবাল ভেরিয়েবল এবং কোনও মেমরির সম্ভবত এটির একটি পয়েন্টার থাকতে পারে। উদাহরণস্বরূপ স্থানীয়দের বাদে সমস্ত কিছুই যাদের ঠিকানা পালাতে পারে নি, সমস্ত কল জুড়ে মেমরির সাথে সিঙ্কে থাকতে হবে। এটি asm এ লেখা ফাংশনগুলিতে স্পষ্টতই, তবে গ্রন্থাগারের ফাংশনেও প্রযোজ্য। আপনি যদি লিংক-সময় অপ্টিমাইজেশন সক্ষম না করে থাকেন তবে এটি পৃথক অনুবাদ ইউনিট (উত্স ফাইল )গুলিতেও প্রযোজ্য।


এটি গ্লিবসি অংশ হিসাবে নিরাপদ তবে অন্যথায় নয়

সর্বাধিক গুরুত্বপূর্ণ বিষয়টি হ'ল এটি strlenঅন্য কোনও কিছুর সাথে ইনলাইন করতে পারে না। এটি তার পক্ষে নিরাপদ নয়; এটিতে কঠোর-আলিয়াজিং ইউবি রয়েছে ( charএকটি মাধ্যমে ডেটা পড়া unsigned long*)। char*অন্য ওরফে কিছু অনুমতি দেওয়া হয় কিন্তু বিপরীত হয় না সত্য

এটি সামনের সময়ের সংকলিত লাইব্রেরি (গ্লিবসি) এর জন্য একটি লাইব্রেরি ফাংশন। এটি কলকারীদের সাথে লিঙ্ক-টাইম-অপ্টিমাইজেশানের সাথে মিলিত হবে না। এর অর্থ এটির একা একা থাকা সংস্করণের জন্য নিরাপদ মেশিন কোডে সংকলন করতে হবে strlen। এটি পোর্টেবল / নিরাপদ সি হতে হবে না

জিএনইউ সি লাইব্রেরিতে কেবল জিসিসির সাথে সংকলন করতে হবে। স্পষ্টতই এটি জঞ্জাল বা আইসিসি দিয়ে সংকলন করার জন্য সমর্থিত নয় , যদিও তারা জিএনইউ এক্সটেনশানগুলিকে সমর্থন করে। জি সি সি হ'ল আগাম সংকলক যা একটি সি উত্স ফাইলটিকে মেশিন কোডের একটি অবজেক্ট ফাইলে পরিণত করে। কোনও দোভাষী না, সুতরাং এটি সংকলনের সময় ইনলাইন না করা পর্যন্ত, মেমরির বাইটগুলি মেমরিতে কেবল বাইট হয়। অর্থাত্ কড়া-আলিয়াজিং ইউবি বিপজ্জনক নয় যখন বিভিন্ন ধরণের অ্যাক্সেসগুলি বিভিন্ন ফাংশনে ঘটে যা একে অপরের সাথে ইনলাইন করে না।

মনে রাখবেন যে strlenএর আচরণটি আইএসও সি স্ট্যান্ডার্ড দ্বারা সংজ্ঞায়িত করা হয়েছে । এই ফাংশনটির নামটি বাস্তবায়নের অংশ । জিসিসি মত কম্পাইলার এমনকি একটি বিল্ট-ইন ফাংশন যদি না আপনি ব্যবহার নাম চিকিত্সা -fno-builtin-strlen, তাই strlen("foo")একটি কম্পাইল-টাইম ধ্রুবক হতে পারে 3। গ্রন্থাগারের সংজ্ঞাটি কেবল তখনই ব্যবহৃত হয় যখন জিসিসি তার নিজস্ব রেসিপি বা কোনও কিছু অন্তর্ভুক্ত না করে পরিবর্তে কোনও কলটি প্রেরণ করার সিদ্ধান্ত নেয়।

সংকলনের সময় ইউবি যখন সংকলকের কাছে দৃশ্যমান নয় , আপনি স্যান মেশিন কোড পান। মেশিন কোডটি নো-ইউবি মামলার জন্য কাজ করতে হবে এবং আপনি চাইলেও , এসএমের পক্ষে পয়েন্ট-টু মেমোরিতে কলকারী কীভাবে ডেটা ব্যবহার করতেন তা সনাক্ত করার উপায় নেই।

গ্লিবসি একটি স্ট্যান্ড-একা স্ট্যাটিক বা গতিশীল লাইব্রেরিতে সংকলিত হয়েছে যা লিঙ্ক-টাইম অপ্টিমাইজেশানের সাথে ইনলাইন করতে পারে না। গ্লিবিসি-র বিল্ড স্ক্রিপ্টগুলি কোনও প্রোগ্রামের অভ্যন্তরে প্রবেশের সময় লিঙ্ক-টাইম অপ্টিমাইজেশনের জন্য মেশিন কোড + জিসিসি জিমপ্লে অভ্যন্তরীণ উপস্থাপনাযুক্ত "ফ্যাট" স্ট্যাটিক লাইব্রেরি তৈরি করে না। (অর্থাত্ মূল প্রোগ্রামে লিঙ্ক-টাইম অপ্টিমাইজেশনে libc.aঅংশ নেবে না -flto)) গ্লিবিসি তৈরি করা সেই লক্ষ্যে প্রকৃতপক্ষে.c নিরাপদ হবে যা প্রকৃতপক্ষে এটি ব্যবহার করে

আসলে @zwol মন্তব্য হিসাবে, গ্লিবিসি নিজেই তৈরি করার সময় এলটিও ব্যবহার করা যাবে না , কারণ "ব্রিটল" কোডটির কারণে এটি যদি ভঙ্গ করতে পারে যদি গ্লিবিক উত্স ফাইলগুলির মধ্যে ইনলাইনিং করা সম্ভব হত। (কিছু অভ্যন্তরীণ ব্যবহার রয়েছে strlen, উদাহরণস্বরূপ সম্ভবত printfবাস্তবায়নের অংশ হিসাবে )


এটি strlenকিছু অনুমান করে:

  • CHAR_BIT8 এর একাধিক । সমস্ত জিএনইউ সিস্টেমে সত্য। পজিক্স 2001 এমনকি গ্যারান্টি দেয় CHAR_BIT == 8। (এটি কিছু ডিএসপির মতো CHAR_BIT= 16বা এর জন্য সিস্টেমগুলির জন্য নিরাপদ বলে মনে হয় 32; স্বাক্ষরবিহীন-প্রলুগ লুপটি সর্বদা 0 পুনরাবৃত্তি চলবে যদি sizeof(long) = sizeof(char) = 1প্রতিটি পয়েন্টার সর্বদা সারিবদ্ধ থাকে এবং p & sizeof(long)-1সর্বদা শূন্য থাকে)) তবে আপনার যদি অ-ASCII অক্ষর সেট থাকে যেখানে অক্ষর 9 হয় বা 12 বিট প্রশস্ত, 0x8080...এটি ভুল প্যাটার্ন।
  • (সম্ভবত) unsigned long4 বা 8 বাইট হয়। অথবা সম্ভবত এটি unsigned long8 টি পর্যন্ত কোনও আকারের জন্য কাজ করবে এবং এটি এটির assert()জন্য একটি ব্যবহার করে।

এই দুটি সম্ভাব্য ইউবি নয়, তারা কিছু সি বাস্তবায়নের কেবল অ-বহনযোগ্যতা। এই কোডটি প্ল্যাটফর্মগুলিতে যেখানে এটি কাজ করে সেখানে সি প্রয়োগের অংশ (বা ছিল) , সুতরাং এটি ঠিক।

পরবর্তী অনুমানটি সম্ভাব্য সি ইউবি:

  • কোনও প্রান্তিক লোড যাতে কোনও বৈধ বাইট থাকে তা দোষ দিতে পারে না , এবং যতক্ষণ না আপনি প্রকৃতপক্ষে অবজেক্টের বাইরের বাইটগুলি উপেক্ষা করবেন ততক্ষণ নিরাপদ থাকে। (প্রতিটি জিএনইউ সিস্টেমে সত্য হিসাবে সত্য, এবং সমস্ত সাধারণ সিপিইউতে সত্য যেহেতু মেমরি সুরক্ষা প্রান্তিকৃত পৃষ্ঠার গ্রানুলারিটির সাথে ঘটে x একই পৃষ্ঠায় x86 এবং x64 এর মধ্যে কোনও বাফারের শেষে পড়া কি নিরাপদ ? সিবিতে সুরক্ষিত থাকলে নিরাপদ ? সংকলনের সময় দৃশ্যমান নয় in ইনলাইনিং ব্যতীত এখানেই এটি। সংকলক প্রমাণ করতে পারে না যে প্রথমটি পড়া শেষ 0ইউবি; এটি উদাহরণস্বরূপ একটি সি char[]অ্যারে হতে পারে {1,2,0,3})

এই শেষ পয়েন্টটি এখানে কোন সি এর অবজেক্টের শেষে পড়া নিরাপদ করে তোলে। বর্তমান সংকলকগুলির সাথে সন্নিবেশ করা সত্ত্বেও এটি বেশ নিরাপদ কারণ আমি মনে করি তারা বর্তমানে কার্যকর করে না যে মৃত্যুদন্ড কার্যকর করার পথটি বোঝা যায় না। তবে যাইহোক, আপনি যদি কখনও এই ইনলাইনটি ছেড়ে দেন তবে কঠোর আলিয়াজিং ইতিমধ্যে শোস্টোপার।

তারপরে আপনার লিনাক্স কার্নেলের পুরানো অনিরাপদ memcpy সিপিপি ম্যাক্রোর মতো সমস্যা রয়েছে যা পয়েন্টার-কাস্টিং unsigned long( জিসিসি, স্ট্রাইক-এলিয়াসিং এবং হরর স্টোরিস ) ব্যবহার করে।

এটি strlenসেই যুগে ফিরে আসে যখন আপনি সাধারণভাবে এই জাতীয় জিনিসগুলি নিয়ে পালিয়ে যেতে পারতেন ; এটি জিসিসি 3 এর আগে "কেবলমাত্র ইনলাইনিং না করলে" ক্যাভ্যাট ব্যতীত বেশ সুরক্ষিত থাকত।


কল / রিট সীমানা জুড়ে যখন কেবল ইউবি প্রদর্শিত হয় তা আমাদের ক্ষতি করতে পারে না। (উদাহরণস্বরূপ এটিকে কাস্ট করার char buf[]জন্য একটি অ্যারের পরিবর্তে কল করা )। একবার মেশিনের কোডটি পাথরে সেট হয়ে গেলে এটি কেবল মেমরিতে বাইটগুলি নিয়ে কাজ করে। একটি অন-ইনলাইন ফাংশন কলকে ধরে নিতে হবে যে কলি কোনও / সমস্ত মেমরি পড়ে।unsigned long[]const char*


কঠোর-এলিয়জিং ইউবি ছাড়াই এটি নিরাপদে লেখা ing

জিসিসি টাইপ অ্যাট্রিবিউটmay_alias একটি টাইপ হিসাবে একই ওরফে-কিছু চিকিত্সা দেয় char*। (@ কনরাডবোরভস্ক প্রস্তাবিত)। জিসিসির শিরোনামগুলি বর্তমানে x86 সিমডি ভেক্টর প্রকারের জন্য এটি ব্যবহার করে __m128iযাতে আপনি সর্বদা নিরাপদে করতে পারেন _mm_loadu_si128( (__m128i*)foo )। (দেখুন কি হার্ডওয়্যার ভেক্টর পয়েন্টার এবং এটির সাথে সম্পর্কিত টাইপটি একটি অপরিজ্ঞাত আচরণের মধ্যে `পুনরায় ব্যাখ্যা_কাস্টিং হয়? এটি কী বোঝায় এবং এর অর্থ কী না সে সম্পর্কে আরও তথ্যের জন্য))

strlen(const char *char_ptr)
{
  typedef unsigned long __attribute__((may_alias)) aliasing_ulong;

  aliasing_ulong *longword_ptr = (aliasing_ulong *)char_ptr;
  for (;;) {
     unsigned long ulong = *longword_ptr++;  // can safely alias anything
     ...
  }
}

আপনি এর aligned(1)সাথে কোনও প্রকারটি প্রকাশ করতেও ব্যবহার করতে পারেন alignof(T) = 1
typedef unsigned long __attribute__((may_alias, aligned(1))) unaligned_aliasing_ulong;

আইএসওতে এলিয়াসিং লোড প্রকাশ করার একটি বহনযোগ্য উপায় রয়েছেmemcpy , যা আধুনিক সংকলকরা জানেন যে কীভাবে একক লোড নির্দেশ হিসাবে ইনলাইন করতে হয়। যেমন

   unsigned long longword;
   memcpy(&longword, char_ptr, sizeof(longword));
   char_ptr += sizeof(longword);

এটি স্বাক্ষরবিহীন লোডগুলির জন্যও কাজ করে কারণ এক সময় অ্যাক্সেস memcpyবাই বাই char-অ্যাক্সেস হিসাবে কাজ করে। তবে অনুশীলনে আধুনিক সংকলকগণ memcpyখুব ভালভাবে বুঝতে পারেন ।

এখানে বিপদটি হ'ল যদি জিসিসি নিশ্চিতভাবে জানত না যে char_ptrএটি শব্দ-সংযুক্ত রয়েছে, তবে এটি এটিকে কিছু প্ল্যাটফর্মগুলিতে ইনলাইন করবে না যেগুলি asm এ স্বাক্ষরযুক্ত লোডগুলিকে সমর্থন করবে না। উদাহরণস্বরূপ, এমআইপিএস 64 আর r এর আগে এমআইপিএস বা তার থেকেও পুরানো এআরএম। আপনি যদি memcpyকেবল একটি শব্দ লোড করার জন্য একটি প্রকৃত ফাংশন কল পেয়ে থাকেন (এবং এটি অন্য স্মৃতিতে রেখে যান) তবে এটি একটি বিপর্যয় হবে। কোড কখন পয়েন্টার সারিবদ্ধ করে জিসিসি কখনও কখনও দেখতে পারে। বা চার-এ-এ-টাইম লুপের পরে যা আপনি ব্যবহার করতে পারেন এমন একটি সীমান্ত সীমানায় পৌঁছে যায়
p = __builtin_assume_aligned(p, sizeof(unsigned long));

এটি পঠিত-অতীত-অবজেক্টটিকে সম্ভাব্য ইউবি এড়াতে পারে না, তবে বর্তমান জিসিসির সাথে এটি কার্যকরভাবে বিপজ্জনক নয়।


কেন হ্যান্ড-অপ্টিমাইজড সি উত্স প্রয়োজনীয়: বর্তমান সংকলকগুলি যথেষ্ট ভাল নয়

যখন আপনি বহুল ব্যবহৃত-স্ট্যান্ডার্ড লাইব্রেরি ফাংশনটির জন্য প্রতিবারের ড্রপ কর্মক্ষমতা চান তখন হ্যান্ড-অপ্টিমাইজড এ্যাসটি আরও ভাল হতে পারে। বিশেষত যেমন কিছু জন্য memcpy, কিন্তু strlen। সেক্ষেত্রে এসএসই 2 এর সুবিধা নেওয়ার জন্য x86 ইন্টারনসনিক সহ সি ব্যবহার করা খুব সহজ হবে না।

তবে এখানে আমরা কেবল আইএসএ-নির্দিষ্ট বৈশিষ্ট্য ছাড়াই একটি নিষ্পাপ বনাম বিট্যাক সি সংস্করণ সম্পর্কে কথা বলছি।

(আমি মনে করি যে আমরা এটি একটি প্রদত্ত হিসাবে গ্রহণ করতে পারি যা strlenএটি যথেষ্ট পরিমাণে ব্যবহৃত হয়েছে যে এটি যত দ্রুত সম্ভব চালানো গুরুত্বপূর্ণ। তাই প্রশ্নটি উত্সব হয়ে যায় যে আমরা সহজ উত্স থেকে দক্ষ মেশিন কোড পেতে পারি কিনা No না, আমরা পারব না))

বর্তমান জিসিসি এবং ক্ল্যাং স্বয়ংক্রিয়-ভেক্টরাইজিং লুপগুলিতে সক্ষম নয় যেখানে পুনরাবৃত্তির গণনা প্রথম পুনরাবৃত্তির আগে জানা যায় না । (উদাহরণস্বরূপ , প্রথম পুনরাবৃত্তিটি চালানোর আগে লুপটি কমপক্ষে ১ run টি পুনরাবৃত্তি চলবে কিনা তা খতিয়ে দেখতে হবে) উদাহরণস্বরূপ অটোভেস্টোরাইজিং মেমকিপি সম্ভব (স্পষ্ট দৈর্ঘ্যের বাফার) তবে স্ট্রাইক বা স্ট্রেন (অন্তর্নিহিত দৈর্ঘ্যের স্ট্রিং) নয়, বর্তমান কম্পাইলার।

এর মধ্যে অনুসন্ধানের লুপগুলি, বা কোনও ডেটা নির্ভর নির্ভর অন্য কোনও লুপ অন্তর্ভুক্ত রয়েছে if()break

আইসিসি (x86 এর জন্য ইন্টেলের সংকলক) কিছু অনুসন্ধান লুপগুলি স্বয়ংক্রিয়ভাবে ভেক্টরাইজ করতে পারে, তবে এখনও কেবল strlenওপেনবিএসডি-র লাইবসি ব্যবহারের মতো একটি সরল / নিষ্পাপ সি এর জন্য নির্দোষ বাইট-এ-এ-টাইম এসএম তৈরি করে। ( গডবোল্ট ) ( @ পেসকের উত্তর থেকে )।

strlenবর্তমান সংকলকগুলির সাথে পারফরম্যান্সের জন্য একটি হ্যান্ড-অপ্টিমাইজড libc প্রয়োজনীয় । একবারে 1 বাইটে যাওয়া (প্রশস্ত সুপারসকলার সিপিইউগুলিতে চক্র প্রতি 2 বাইট আনারোলিং সহ) করুণ হয়ে উঠতে পারে যখন প্রধান মেমরিটি প্রতি চক্রের প্রায় 8 বাইট রাখতে পারে এবং L1d ক্যাশে প্রতি চক্র 16 থেকে 64 সরবরাহ করতে পারে। (হাসওয়েল এবং রাইজেনের পর থেকে আধুনিক মূলধারার x86 সিপিইউগুলিতে চক্রের জন্য 2x 32-বাইট লোড যদিও 256-বিট ভেক্টর সহ, AVX512VL + BW মুখোশযুক্ত একটি মাস্কের সাথে তুলনা করে ktestবা এর উওস / পুনরাবৃত্তি হ্রাস করে আরও হাইপারথ্রেডিং বন্ধুত্বপূর্ণ kortestকরতে পারে strlen))

আমি এখানে নন- x86 অন্তর্ভুক্ত করছি, এটি "16 বাইট"। উদাহরণস্বরূপ বেশিরভাগ আআরচ 64৪ সিপিইউ কমপক্ষে এটি করতে পারে, আমার ধারণা, এবং আরও কিছু অবশ্যই। এবং কিছু strlenলোড ব্যান্ডউইথ সঙ্গে রাখা জন্য যথেষ্ট এক্সিকিউশন থ্রুটপুট আছে ।

অবশ্যই যে প্রোগ্রামগুলি বড় স্ট্রিংগুলির সাথে কাজ করে তাদের সাধারণত দৈর্ঘ্যের সি স্ট্রিংগুলির দৈর্ঘ্যটি প্রায়শই পুনরায় করা এড়াতে দৈর্ঘ্যের উপর নজর রাখতে হবে। তবে স্বল্প থেকে মাঝারি দৈর্ঘ্যের পারফরম্যান্সটি এখনও হাতে লিখিত প্রয়োগগুলি থেকে উপকৃত হয়েছে এবং আমি নিশ্চিত যে কিছু প্রোগ্রাম মাঝারি দৈর্ঘ্যের স্ট্রিংগুলিতে স্ট্রেন ব্যবহার করে শেষ হয়।


12
কয়েকটি নোট: (1) বর্তমানে গিসিবি ব্যতীত অন্য কোনও সংকলক দিয়ে গ্লিবসি নিজেই সংকলন করা সম্ভব নয়। (২) লিঙ্ক-টাইম অপ্টিমাইজেশানগুলি সক্ষম করে গিলিবিসি নিজেই সংকলন করা বর্তমানে সম্ভব নয়, কারণ এই ধরণের ক্ষেত্রে সুনির্দিষ্টভাবে করা হয়, যেখানে ইনলাইনিংয়ের অনুমতি দেওয়া থাকলে সংকলকটি ইউবি দেখতে পাবে। (3) CHAR_BIT == 8একটি পসিক্স প্রয়োজনীয়তা (-2001 রেভ হিসাবে; এখানে দেখুন )। (4) সি ফ্যালব্যাক বাস্তবায়ন strlenকিছু সমর্থিত সিপিইউগুলির জন্য ব্যবহৃত হয়, আমি বিশ্বাস করি যে সর্বাধিক সাধারণ একটি এমআইপিএস।
zwol

1
মজার বিষয় হল, কড়া-এলিয়াসিং ইউবি __attribute__((__may_alias__))বৈশিষ্ট্যটির ব্যবহার করে স্থির করা যেতে পারে (এটি পোর্টেবল নয়, তবে এটি গ্লিবিকের জন্য জরিমানা হওয়া উচিত)।
কনরাড বোরোস্কি

1
@ সেবাস্তিয়ানআরডেল: আপনি কোনও মাধ্যমে কোনও বস্তু পড়তে / লিখতে পারেন char*, তবে এটি এখনও একটি ইউ এর মাধ্যমে কোনও char অবজেক্ট (উদাহরণস্বরূপ অংশ char[]) পড়তে / লিখতে UB long*কঠোর আলিয়াজিংয়ের নিয়ম এবং 'চর *' পয়েন্টার
পিটার কর্ডস

1
সি এবং সি ++ স্ট্যান্ডার্ডগুলি বলে যে CHAR_BITএটি কমপক্ষে 8 ( সিভি 11 এর কিউভি এনেক্সেক্স ই) হওয়া আবশ্যক, সুতরাং charভাষা আইনজীবীর পক্ষে কমপক্ষে--বিট উদ্বেগের বিষয় হওয়া উচিত নয়। এটি প্রয়োজনীয়তা দ্বারা অনুপ্রাণিত হয়েছিল, "ইউটিএফ − 8 স্ট্রিং আক্ষরিক জন্য, অ্যারের উপাদানগুলি টাইপ করে থাকে charএবং ইউটিএফ − 8 এ এনকোডযুক্ত মাল্টিবাইট অক্ষর অনুক্রমের অক্ষর দিয়ে শুরু করা হয়” "
ডেভিস্লোর 28'19

2
দেখে মনে হচ্ছে এই বিশ্লেষণটি কোনও প্যাচ প্রস্তাব দেওয়ার পক্ষে বর্তমানে একটি অক্ষম উত্তর বাদ দিয়ে বর্তমানে অক্ষম অপটিমেশনের মুখে কোডটিকে আরও শক্তিশালী করে তোলে a
উত্সাহক

61

আপনার লিঙ্ক করা ফাইলটির মন্তব্যে এটি ব্যাখ্যা করা হয়েছে:

 27 /* Return the length of the null-terminated string STR.  Scan for
 28    the null terminator quickly by testing four bytes at a time.  */

এবং:

 73   /* Instead of the traditional loop which tests each character,
 74      we will test a longword at a time.  The tricky part is testing
 75      if *any of the four* bytes in the longword in question are zero.  */

সি তে দক্ষতা সম্পর্কে বিস্তারিত যুক্তি দেওয়া সম্ভব।

এই কোডটি যেমন করে একই সময়ে একাধিক বাইট পরীক্ষা করার চেয়ে নাল সন্ধানের জন্য স্বতন্ত্র অক্ষরগুলির মাধ্যমে পুনরাবৃত্তি করা কম দক্ষ।

অতিরিক্ত জটিলতাটি একবারে একাধিক বাইট পরীক্ষা করা শুরু করার জন্য (পরীক্ষার অধীনে স্ট্রিংটি সঠিক জায়গায় সারিবদ্ধ করা হয়েছে (মন্তব্যগুলিতে বর্ণিত লং ওয়ার্ডের সীমানা বরাবর)) এবং এই অনুমানগুলি নিশ্চিত করার প্রয়োজন থেকে অতিরিক্ত জটিলতা আসে comes কোড ব্যবহার করার সময় ডেটাটাইপগুলির আকারগুলির লঙ্ঘন হয় না।

ইন অধিকাংশ (কিন্তু সব নয়) আধুনিক সফটওয়্যার উন্নয়ন, দক্ষতা বিস্তারিত এই মনোযোগ প্রয়োজন হয় তাহলে, বা অতিরিক্ত কোড জটিলতা খরচ অধিকারী না নয়।

এটির মতো দক্ষতার দিকে মনোনিবেশ করা আপনার এক জায়গায় অর্থ হ'ল আদর্শ লাইব্রেরিতে যেমন উদাহরণটি আপনি সংযুক্ত করেছেন like


আপনি যদি শব্দের সীমানা সম্পর্কে আরও জানতে চান তবে এই প্রশ্নটি এবং এই দুর্দান্ত উইকিপিডিয়া পৃষ্ঠাটি দেখুন


39

এখানে দুর্দান্ত উত্তরের পাশাপাশি, আমি এটি উল্লেখ করতে চাই যে প্রশ্নের সাথে লিঙ্কিত কোডটি জিএনইউ এর প্রয়োগের জন্য strlen

এর OpenBSD বাস্তবায়নstrlen খুব প্রশ্নে প্রস্তাবিত কোডে অনুরূপ। একটি বাস্তবায়নের জটিলতা লেখক দ্বারা নির্ধারিত হয়।

...
#include <string.h>

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

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

DEF_STRONG(strlen);

সম্পাদনা : আমি ওপেনবিএসডি কোডটি উপরে উল্লিখিত বলে মনে করি যে আইএসএর নিজস্ব অসম বাস্তবায়ন নেই। strlenস্থাপত্যের উপর নির্ভর করে বিভিন্ন বাস্তবায়ন রয়েছে implement Amd64strlen এর কোডটি উদাহরণস্বরূপ is পিটারকর্ডসের মন্তব্য / উত্তরের অনুরূপ যে নন-ফ্যালব্যাক জিএনইউ বাস্তবায়নও asm are


5
এটি ওপেনবিএসডি বনাম জিএনইউ সরঞ্জামগুলিতে অনুকূলিত হওয়া বিভিন্ন মানগুলির একটি খুব সুন্দর চিত্র তুলে ধরেছে।
জেসন

11
এটি গ্লিবিকের বহনযোগ্য ফ্যালব্যাক বাস্তবায়ন। সমস্ত বড় আইএসএর হাতে হাতের লিখিত এএসএম বাস্তবায়ন থাকে গ্লিবিসিতে, সিমডি ব্যবহার করে যখন এটি সহায়তা করে (যেমন x86 তে)। কোড. woboq.org/userspace/glibc/sysdeps/x86_64/m মাল্টিয়ার্ক/… এবং কোড. woboq.org/userspace/glibc/sysdeps/aarch64/m
পিটার কর্ডস

4
এমনকি ওপেনবিএসডি সংস্করণেও ত্রুটি রয়েছে যা আসলটি এড়িয়ে চলে! s - strফলাফলটি যদি প্রতিনিধিত্বমূলক না হয় তবে তার আচরণটি অপরিজ্ঞাত ptrdiff_t
অ্যান্টি হাপাল

1
@ আন্টিহাপালা: জিএনইউ সি-তে সর্বোচ্চ বস্তুর আকার PTRDIFF_MAX। তবে mmapলিনাক্সের তুলনায় এটির চেয়ে আরও বেশি স্মৃতি এখনও সম্ভব (উদাহরণস্বরূপ, x86-64 কার্নেলের অধীনে 32-বিট প্রক্রিয়াতে আমি ব্যর্থতা শুরুর আগে প্রায় 2.7GB সংশ্লেষ করতে পারি) m ওপেনবিএসডি সম্পর্কে আইডিকে; কার্নেলটি returnসেগফল্টিং বা আকারের মধ্যে না থেমে পৌঁছানো অসম্ভব করে দিতে পারে । তবে হ্যাঁ, আপনি ভাবেন যে রক্ষণাত্মক কোডিং যা তাত্ত্বিক সি ইউবি এড়িয়ে চলে এমন কিছু হবে যা ওপেনবিএসডি করতে চাইবে। যদিও strlenইনলাইন করতে পারে না এবং বাস্তব সংকলকরা কেবল এটি একটি বিয়োগকে সংকলন করবে।
পিটার

2
@ পিটারকর্ডস ঠিক ওপেনবিএসডি-তে একই জিনিস, উদাহরণস্বরূপ i386 সমাবেশ: cvsweb.openbsd.org/cgi-bin/cvsweb/src/lib/libc/arch/i386/string/…
ডিসকাস্ট

34

সংক্ষেপে, এটি একটি পারফরম্যান্স অপটিমাইজেশন যা স্ট্যান্ডার্ড লাইব্রেরি এটি কী সংকলকটি সংকলিত তা জেনে যা করতে পারে - আপনি কোনও স্ট্যান্ডার্ড লাইব্রেরি না লিখলে এবং কোনও নির্দিষ্ট সংকলক নির্ভর করতে না পারলে আপনার এ জাতীয় কোডটি লেখা উচিত নয়। বিশেষত, এটি একই সময়ে বাইটের প্রান্তিককরণ সংখ্যা প্রক্রিয়াজাত করছে - 32-বিট প্ল্যাটফর্মের 4, 64৪-বিট প্ল্যাটফর্মগুলিতে 8। এর অর্থ এটি ন্যাভ বাইট পুনরাবৃত্তির চেয়ে 4 বা 8 গুণ দ্রুত হতে পারে।

এটি কীভাবে কাজ করে তা ব্যাখ্যা করতে নীচের চিত্রটি বিবেচনা করুন। এখানে 32-বিট প্ল্যাটফর্ম ধরে নিন (4 বাইট প্রান্তিককরণ)।

যাক, "হ্যালো, বিশ্ব!" এর "এইচ" চিঠিটি বলা যাক স্ট্রিংয়ের জন্য একটি আর্গুমেন্ট হিসাবে সরবরাহ করা হয়েছিল strlen। যেহেতু সিপিইউ জিনিসগুলিকে মেমরিতে একত্রিত করা পছন্দ করে (আদর্শভাবে address % sizeof(size_t) == 0), ধীরে ধীরে পদ্ধতি ব্যবহার করে প্রান্তিককরণের আগে বাইটগুলি বাই বাই বাই প্রসেস করা হয়।

তারপরে, প্রতিটি প্রান্তিককরণ-আকারের (longbits - 0x01010101) & 0x80808080 != 0অংশের জন্য, এটি গণনা করে পরীক্ষা করে দেখায় যে কোনও পূর্ণসংখ্যার মধ্যে থাকা কোনও বাইট শূন্য কিনা। এই গণনাটিতে একটি মিথ্যা ইতিবাচক থাকে যখন কমপক্ষে কোনও একটি বাইটের চেয়ে বেশি হয় 0x80তবে প্রায়শই এটির কাজ না করা উচিত। যদি এটি না হয় (যেমন এটি হলুদ অঞ্চলে থাকে) তবে প্রান্তিককরণের আকার দ্বারা দৈর্ঘ্য বৃদ্ধি করা হয়।

যদি কোনও পূর্ণসংখ্যার মধ্যে থাকা কোনও বাইট শূন্য (বা 0x81) রূপান্তরিত হয় , তবে শূন্যের অবস্থান নির্ধারণ করতে স্ট্রিংটি বাই-বাই বাইট চেক করা হয়।

এটি একটি সীমার বাইরে অ্যাক্সেস তৈরি করতে পারে, তবে এটি একটি প্রান্তিককরণের মধ্যে রয়েছে বলে, এটি সূক্ষ্ম না হওয়ার বেশি সম্ভাবনা রয়েছে, মেমরি ম্যাপিং ইউনিটগুলিতে সাধারণত বাইট লেভেল স্পষ্টতা থাকে না।


এই বাস্তবায়নটি গ্লিবসি-র অংশ। জিএনইউ সিস্টেম পৃষ্ঠা গ্র্যানুলারিটির সাথে মেমরির সুরক্ষা দেয়। সুতরাং হ্যাঁ, একটি সংযুক্ত লোড যা কোনও বৈধ বাইট অন্তর্ভুক্ত নিরাপদ।
পিটার কর্ডস

size_tসারিবদ্ধ হওয়ার নিশ্চয়তা নেই।
এসএস অ্যান

32

আপনি কোডটি সঠিক, রক্ষণাবেক্ষণযোগ্য এবং দ্রুত হতে চান। এই কারণগুলির আলাদা গুরুত্ব রয়েছে:

"সঠিক" একেবারে প্রয়োজনীয়।

"রক্ষণাবেক্ষণযোগ্য" আপনি কোডটি কীভাবে বজায় রাখতে চলেছেন তার উপর নির্ভর করে: স্ট্রেন 40 বছরেরও বেশি সময় ধরে স্ট্যান্ডার্ড সি লাইব্রেরি ফাংশন হিসাবে কাজ করে। এটি পরিবর্তন হবে না। রক্ষণাবেক্ষণ তাই অতীব গুরুত্বহীন - এই কাজের জন্য।

"দ্রুত": অনেকগুলি অ্যাপ্লিকেশনগুলিতে, স্ট্রাইকপি, স্ট্রেন ইত্যাদি কার্যকর করার সময় একটি উল্লেখযোগ্য পরিমাণ ব্যবহার করে। এই জটিল হিসাবে একই সামগ্রিক গতি অর্জন অর্জন করতে, কিন্তু সংকলক উন্নত করে স্ট্রেনের খুব জটিল বাস্তবায়ন বীরত্বপূর্ণ প্রচেষ্টা গ্রহণ করতে পারে।

দ্রুত হওয়ার আরেকটি সুবিধা রয়েছে: প্রোগ্রামাররা যখন জানতে পারেন যে "স্ট্রলিন" কল করা দ্রুততম পদ্ধতি তারা একটি স্ট্রিংয়ের বাইট সংখ্যাটি পরিমাপ করতে পারে তবে জিনিসগুলিকে আরও দ্রুত করার জন্য তাদের নিজের কোড লেখার জন্য আর প্ররোচিত করা হয় না।

সুতরাং শক্তির জন্য, গতি আরও বেশি গুরুত্বপূর্ণ এবং রক্ষণাবেক্ষণযোগ্যতা খুব কম গুরুত্বপূর্ণ, আপনি যে কোনও কোডটি লিখবেন তার চেয়ে বেশি।

কেন এটি এত জটিল হতে হবে? বলুন আপনার কাছে 1000 বাইট স্ট্রিং রয়েছে। সাধারণ বাস্তবায়ন এক হাজার বাইট পরীক্ষা করবে। একটি বর্তমান বাস্তবায়ন সম্ভবত একবারে bit৪ বিট শব্দ পরীক্ষা করবে, যার অর্থ 125 125৪-বিট বা আট-বাইট শব্দ। এটি এমনকি একবারে 32 বাইট বলার জন্য ভেক্টর নির্দেশাবলীও ব্যবহার করতে পারে যা আরও জটিল এবং আরও দ্রুত হবে। ভেক্টরের নির্দেশাবলীর সাহায্যে কোডটি বাড়ে যা কিছুটা জটিল তবে বেশ সোজা, 64৪ বিট শব্দের মধ্যে আটটি বাইটের যে কোনও একটি শূন্য কিনা তা যাচাই করার জন্য কিছু চালাক কৌশল প্রয়োজন। সুতরাং মাঝারি থেকে দীর্ঘ স্ট্রিংগুলির জন্য এই কোডটি প্রায় চারগুণ দ্রুত হবে বলে আশা করা যায়। স্ট্র্লেনের মতো গুরুত্বপূর্ণ কোনও ফাংশনের জন্য এটি আরও জটিল ফাংশনটি লেখার পক্ষে গুরুত্বপূর্ণ।

পুনশ্চ. কোডটি খুব পোর্টেবল নয়। তবে এটি স্ট্যান্ডার্ড সি লাইব্রেরির অংশ, যা বাস্তবায়নের অংশ - এটি বহনযোগ্য হতে হবে না।

PPS। কেউ একটি উদাহরণ পোস্ট করেছেন যেখানে কোনও ডিবাগিং সরঞ্জাম কোনও স্ট্রিংয়ের শেষের দিকে বাইট অ্যাক্সেস করার বিষয়ে অভিযোগ করেছিল। একটি বাস্তবায়ন ডিজাইন করা যেতে পারে যা নিম্নলিখিতটির গ্যারান্টি দেয়: p যদি বাইটের বৈধ পয়েন্টার হয়, তবে একই মানচিত্রযুক্ত ব্লকের কোনও বাইটে অ্যাক্সেস যা সি স্ট্যান্ডার্ড অনুসারে অপরিজ্ঞাত আচরণ করবে, একটি অনির্ধারিত মান প্রদান করবে।

PPPS। ইন্টেল তাদের পরবর্তী প্রসেসরগুলিতে নির্দেশাবলী যুক্ত করেছে যা স্ট্রাস্টার () ফাংশনের জন্য (একটি স্ট্রিংয়ের একটি স্ট্রাস্টিং সন্ধান করে) জন্য একটি বিল্ডিং ব্লক তৈরি করে। তাদের বিবরণটি মাইন্ড বগলিং, তবে তারা সেই নির্দিষ্ট কাজটি সম্ভবত 100 গুণ দ্রুত করতে পারে। (মূলত, একটি অ্যারে প্রদত্ত "হ্যালো, ওয়ার্ল্ড!" এবং একটি অ্যারে বি দেওয়া 16 বাইট "হ্যালোইলোহেলোএইচ" দিয়ে শুরু হয়েছে এবং আরও বাইট রয়েছে, এটি সূচিত করে যে সূচকটি 15 এর সূচনা শুরুর আগে খ-এ হয় না) ।


অথবা ... আমি খোঁজার করছি যে, আমি স্ট্রিং ভিত্তিক প্রক্রিয়াকরণ অনেকটা করছি এবং সেখানে একটি বোতলের, আমি সম্ভবত পাসকাল স্ট্রিং আমার নিজের সংস্করণ বাস্তবায়ন করা যাচ্ছে না হয় পরিবর্তে strlen উন্নতি ...
Baldrickk

1
কেউ আপনাকে স্ট্রেনের উন্নতি করতে বলে না । তবে এটিকে পর্যাপ্ত পরিমাণে তৈরি করা লোকেরা নিজের স্ট্রিং বাস্তবায়ন করার মতো বাজে কথা এড়িয়ে চলে।
gnasher729


24

সংক্ষিপ্তভাবে: বাইট দ্বারা একটি স্ট্রিং বাইট পরীক্ষা করা সম্ভবত আর্কিটেকচারের জন্য ধীরে ধীরে ধীরে ধীরে ধীরে ধীরে ধীরে ধীরে ধীরে ধীরে ধীরে ধীরে ধীরে ধীরে ধীরে ধীরে বেশি পরিমাণে ডেটা আনতে পারে।

যদি নাল টার্মিনেশনের জন্য চেকটি 32 বা 64 বিট ভিত্তিতে করা যায়, এটি সংস্থাপককে যে পরিমাণ চেক করেছে তার পরিমাণ হ্রাস করে। একটি নির্দিষ্ট সিস্টেমকে মাথায় রেখে লিঙ্কযুক্ত কোড এটি করার চেষ্টা করে। তারা ঠিকানা, প্রান্তিককরণ, ক্যাশে ব্যবহার, নন-স্ট্যান্ডার্ড সংকলক সেটআপগুলি ইত্যাদি সম্পর্কে অনুমান করে

আপনার উদাহরণ হিসাবে বাইট বাই পাঠ করা একটি 8 বিট সিপিইউতে একটি বুদ্ধিমান পন্থা হবে, বা যখন স্ট্যান্ডার্ড সি-তে লিখিত কোনও পোর্টেবল লিব লেখার সময় would

দ্রুত / ভাল কোড কীভাবে লিখবেন সে সম্পর্কে পরামর্শ দেওয়ার জন্য সি স্ট্যান্ডার্ড লিবসের দিকে নজর দেওয়া ভাল ধারণা নয়, কারণ এটি অ-বহনযোগ্য এবং অ-মানক অনুমান বা খারাপ-সংজ্ঞায়িত আচরণের উপর নির্ভর করবে। আপনি যদি শিক্ষানবিশ হন তবে এ জাতীয় কোড পড়া পড়াশুনার চেয়ে বেশি ক্ষতিকর।


1
অবশ্যই অপ্টিমাইজারটি সম্ভবত এই লুপটি আনরোল করা বা স্বয়ংক্রিয়ভাবে ভেক্টরাইজ করতে পারে এবং প্রাক-ফেচারটি এই অ্যাক্সেসের ধরণটিকে তুচ্ছভাবে সনাক্ত করতে পারে। এই কৌশলগুলি আধুনিক প্রসেসরের ক্ষেত্রে বাস্তবে গুরুত্বপূর্ণ কিনা তা পরীক্ষা করা দরকার। যদি জয় পেতে হয় তবে এটি সম্ভবত ভেক্টর নির্দেশাবলী ব্যবহার করছে।
রুশবিশপ ২

6
@ রসবিশপ: আপনিও এমন আশা করতেন, তবে তা নয়। জিসিসি এবং ক্ল্যাং অটো-ভেক্টরাইজিং লুপগুলিতে সম্পূর্ণভাবে অক্ষম যেখানে প্রথম পুনরাবৃত্তির আগে পুনরাবৃত্তির গণনাটি জানা যায় না। এর মধ্যে অনুসন্ধানের লুপগুলি, বা ডেটা নির্ভর নির্ভর অন্য কোনও লুপ অন্তর্ভুক্ত রয়েছে if()break। আইসিসি এ জাতীয় লুপগুলি স্বয়ংক্রিয়ভাবে ভেক্টরাইজ করতে পারে, তবে আইডিকে এটি একটি নিখুঁত স্ট্রেনের সাথে কতটা ভাল করে তোলে। এবং হ্যাঁ, এসএসই 2 pcmpeqb/ স্ট্রেনের pmovmskbজন্য খুব ভাল, একবারে 16 বাইট পরীক্ষা করে। কোড.woboq.org/userspace/glibc/sysdeps/x86_64/strlen.S.html হ'ল glibc এর এসএসই 2 সংস্করণ। এই প্রশ্নোত্তরও দেখুন ।
পিটার

ওফ, এটি দুর্ভাগ্যজনক। আমি সাধারণত খুব অ্যান্টি-ইউবি থাকি তবে আপনি সি স্ট্রিংগুলিকে প্রযুক্তিগতভাবে ইউবি-এর শেষের-বাফার এমনকি ভেক্টরাইজেশনের অনুমতি দেওয়ার জন্য পড়তে হবে। আমি মনে করি একইভাবে এটিআরএম 64 এ প্রযোজ্য কারণ এটি প্রান্তিককরণের প্রয়োজন।
রাশিবিশপ

-6

অন্যান্য উত্তরগুলির দ্বারা উল্লেখ না করা একটি গুরুত্বপূর্ণ বিষয় হ'ল এফএসএফ মালিকানাধীন কোডটি জিএনইউ প্রকল্পগুলিতে পরিণত না করে তা নিশ্চিত করার বিষয়ে অত্যন্ত সতর্ক। ইন গনুহ স্ট্যান্ডার্ড কোডিং অধীনে মালিকানা প্রোগ্রাম প্রসঙ্গে , একটি উপায় আছে এটি বিদ্যমান মালিকানা কোড সঙ্গে গুলিয়ে ফেলা যাবে না আপনার বাস্তবায়ন সংগঠিত সম্পর্কে একটি সতর্কবার্তা হল:

কোনও পরিস্থিতিতে জিএনইউতে আপনার কাজের জন্য বা চলাকালীন সময়ে ইউনিক্স উত্স কোডটি উল্লেখ করবেন না! (বা অন্য কোনও মালিকানাধীন প্রোগ্রামে))

আপনার যদি কোনও ইউনিক্স প্রোগ্রামের ইন্টার্নালগুলির একটি অস্পষ্ট স্মৃতি রয়েছে, এর অর্থ এই নয় যে আপনি এটির একটি অনুকরণ লিখতে পারবেন না, তবে অভ্যন্তরীণভাবে বিভিন্ন লাইনের সাথে অনুকরণটি সংগঠিত করার চেষ্টা করুন, কারণ এটির বিশদ বিবরণ তৈরি করার সম্ভাবনা রয়েছে ইউনিক্স সংস্করণ অপ্রাসঙ্গিক এবং আপনার ফলাফলের থেকে পৃথক।

উদাহরণস্বরূপ, ইউনিক্স ইউটিলিটিগুলি মেমরির ব্যবহার কমাতে সাধারণত অনুকূলিত হয়েছিল; আপনি যদি পরিবর্তে গতিতে যান তবে আপনার প্রোগ্রামটি খুব আলাদা হবে।

(জোর আমার।)


5
কিভাবে এই প্রশ্নের উত্তর দেয়?
এসএস অ্যান

1
ওপিতে প্রশ্নটি ছিল "এই সরল কোডটি কী আরও ভাল কাজ করবে না?" এবং এটি এমন একটি প্রশ্ন যা সর্বদা প্রযুক্তিগত যোগ্যতার বিষয়ে সিদ্ধান্ত নেওয়া হয় না। জিএনইউর মতো প্রকল্পের জন্য, আইনী সমস্যাগুলি এড়ানো "কোডের আরও ভাল কাজ করা" এর একটি গুরুত্বপূর্ণ অংশ এবং "স্পষ্টত" এর বাস্তবায়ন strlen()বিদ্যমান কোডের মতো বা একইরকম প্রকাশিত হতে পারে। গ্লিবিকের প্রয়োগ হিসাবে "উন্মাদ" এর মতো কিছু এর আগে আর খুঁজে পাওয়া যায় না। rangeCheck11 লাইনের কোডের ওপরে কতটা আইনী বিচলন ছিল তা বিবেচনা করে ! - গুগল / ওরাকল লড়াইয়ে, আমি বলব এফএসএফের উদ্বেগ ভালভাবেই ছিল was
জ্যাক কেলি
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.