1. C++ / Говнокод #4124

    +177

    1. 01
    2. 02
    3. 03
    4. 04
    5. 05
    6. 06
    7. 07
    8. 08
    9. 09
    10. 10
    11. 11
    12. 12
    13. 13
    14. 14
    15. 15
    16. 16
    17. 17
    18. 18
    19. 19
    20. 20
    21. 21
    namespace markup 
    {
        // case sensitive string equality test
        // s_lowcase shall be lowercase string
        inline bool equal(const char* s, const char* s1, size_t length)
        {
          switch(length)
          {
            case 8: if(s1[7] != s[7]) return false;
            case 7: if(s1[6] != s[6]) return false;
            case 6: if(s1[5] != s[5]) return false;
            case 5: if(s1[4] != s[4]) return false;
            case 4: if(s1[3] != s[3]) return false;
            case 3: if(s1[2] != s[2]) return false;
            case 2: if(s1[1] != s[1]) return false;
            case 1: if(s1[0] != s[0]) return false;
            case 0: return true;
            default: return strncmp(s,s1,length) == 0;
          }
        }
    ...

    Запостил: rat4, 29 Августа 2010

    Комментарии (40) RSS

    • Ставлю коду отметку - Гениально! =)
      Ответить
      • ничего нового или гениального.

        почти все компиляторы уже умеют это делать автоматом - и лучше.
        Ответить
        • делать ЭТО? ЧТО это?
          Ответить
          • если вызовешь strncmp() с константной длиной, то при мелких значениях длины компилятор вставит инлайн код для сравнения вместо вызова библиотечной функции.

            http://gcc.gnu.org/onlinedocs/gcc/Other-Builtins.html#Other-Builtins
            Ответить
            • По указанной ссылке ничего не сказано об особенностях оптимизированной версии strncmp().
              Ответить
              • Цитата из третьего абзаца: "Many of these functions are only optimized in certain cases; if they are not optimized in a particular case, a call to the library function will be emitted."

                то что ты видишь в говнокоде сверху, это то что будет сделано самим компилятором на стадии компиляции(!!) - но не всегда, а только если данная оптимизация вызова strncmp() имеет смысл. и она имеет смысл только если входной параметр длина есть константа и эта константа достаточно мелкая. Если параметр длины есть переменная, inline ГК сверху насрет кучи лишнего кода в объектные файлы снижая эффективность кэша кода.
                Ответить
                • Повторяю ещё раз. По ссылке об этом ничего не сказано. Где в этой фразе:
                  "Many of these functions are only optimized in certain cases; if they are not optimized in a particular case, a call to the library function will be emitted." сказано про константы и ее размер?
                  Не спорю, что это может быть действительно так, но в указанной статье об этом не сказано.
                  Ответить
              • самый простой пример оптимизаций этого типа это "memcpy( &c1, &c2, 1 )" - почти все компиляторы уберут memcpy() и сгенерят просто mov байта.
                Ответить
        • Компиляторы много чего делают в целях оптимизации.
          Это же не значит, что нужно так писать.

          Не хотел бы я разбирать программы, написанные компилятором
          Ответить
    • Типа сначала хватало и 8 символов, а потом добавили default.
      Ответить
      • Интересная мысль, просмотрел весь код и заметил, что length больше 8 нигде не передаётся.
        Ответить
        • проверь что ваш компилер эту оптимизацию автоматом уже не делает. MSVC и новые GCC это умеют.
          Ответить
        • Сейчас ещё выяснится, что это имена файлов для DOS.
          Ответить
    • хм, такое даже школоло не напишет на лабу...
      Ответить
    • Оптимизация?
      if (length < 9) {
        while (length--)
          if (s1[length] != s[length]) return false;
        return true;
      }
      return strncmp(s, s1, length) == 0;
      Не лучше?
      Ответить
      • strncmp("aa", "bb", 0)
        Ответить
        • >strncmp("aa", "bb", 0)
          Что вы хотели этим сказать?
          Ответить
        • Кажется я понял :))
          При length<=0 будет жопа :)
          Ответить
          • Хорошо хоть за два дня.
            при нуле будет тру вне зависимости от строк
            при отрицательных значениях - смотри исходник strncmp, и то, только
            если у вас получится засунуть в sizte_t (unsigned integral) отрицательное значение. энивей it's fun.
            Ответить
            • >Хорошо хоть за два дня.
              Мысли надо выражать чОтче :)
              А то ребус, понимаешь, какой-то.
              Ответить
            • >при нуле будет тру
              Так и должно быть. В strncmp() по крайней мере.
              А предложенная "оптимизация" будет сбоить.
              Ответить
          • Кажется, я не понял.
            А что не так при length == 0 ?
            Для length < 0 не проверялось, ибо unsigned. Кстати, например, -2 вполне сойдёт за 4294967294, при этом strncmp() не зайдёт дальше конца самой короткой строки.
            Ответить
            • >А что не так при length == 0 ?
              s1[-1] != s[-1] или
              s1[4294967295] != s[4294967295] для unsigned
              Ответить
              • while (length--) { }
                это, грубо говоря,
                next:
                if (length == 0) goto quit;
                else {
                  length = length - 1;
                  // тут сравнение
                  goto next;
                }
                quit:
                length = length - 1;
                Где ошибаюсь?
                Ответить
                • Вы правы. Бес попутал :)
                  Ответить
                  • Чёрненький такой, шарообразный ;)
                    Ответить
                    • Ага. С маленькими ручками.
                      Ответить
                      • вы вообще про что?

                        int main(void) {
                        const char* alpha = "bla-bla";
                        const char* beta = "bla-bla";
                        //fun starts here
                        cout << alpha[111] << endl;
                        cout << beta[111] << endl;
                        return 0;
                        }

                        $ g++ cCh.cpp
                        $ ./a.out
                        }
                        ?
                        Ответить
                        • а оказывается - что нет.

                          /* $OpenBSD: strncmp.c,v 1.7 2005/08/08 08:05:37 espie Exp $ */
                          int
                          strncmp(const char *s1, const char *s2, size_t n)
                          {
                          if (n == 0)
                          return (0);
                          do {
                          if (*s1 != *s2++)
                          return (*(unsigned char *)s1 - *(unsigned char *)--s2);
                          if (*s1++ == 0)
                          break;
                          } while (--n != 0);
                          return (0);
                          }

                          строки перебираются сначала, не с конца или середины. поэтому желанного s1[4294967295] не будет. а жаль.
                          Ответить
      • почему бы не сделать по-ебанутому!?

        const size_t MAX_LEN = 9;
        while (length < MAX_LEN) {
          --length;
          if (s1[length] != s[length]) 
            return false;
        }
        
        return (!length)?true:strncmp(s + MAX_LEN, s1 + MAX_LEN, length) == 0;
        Ответить
        • Что-то у вас не то. Условие выхода из цикла length >= MAX_LEN при этом length уменьшается.
          Так и до переполнения в минус недалеко.
          Хотя скорее будет Access violation.
          Ну и последний ретурн вообще какой-то убогий.
          Ответить
        • inline bool equal(const char* s, const char* s1, size_t length)
          {
          	const size_t easyLen = 8;
          	
          	if( length <= 0 ) return true;
          	
          	if( length <= easyLen )
          	{
          		int index = length;
          		
          		while( index-- )
          		{
          			if( s[index] != s1[index] ) return false;
          		}
          		return true;
          	}
          	
          	return strncmp(s,s1,length) == 0;
          }
          Ответить
          • заменить if( length <= 0 ) return true;
            на if( length == 0 ) return true; если size_t есть unsigned.
            Ну, или внести условие в следующий if.
            Если найдете ошибку - напишите.
            Ответить
            • int index выкинуть, использовать length.
              Ответить
              • Да-да. Об этом как раз в другой теме с вашим тёзкой обсуждаем :)))
                Ответить
              • нако
                bool equal(const char *ls, const char *rs, size_t length)
                {
                	static const size_t DEFAULT_MAX_LENGTH = 10;
                	const size_t MAX_LENGTH = (length <= DEFAULT_MAX_LENGTH)?0:length - DEFAULT_MAX_LENGTH;
                	
                	for(; length >= MAX_LENGTH; --length)
                		if(ls[length] != rs[length])
                			return false;
                
                	return !strncmp(ls, rs, length);
                }
                Ответить
    • Если это было сделано на основе анализа производительности кода и дало в результате ожидаемый эффект - то это ни разу не говнокод, а весьма элегантное применение конструкции типа классического Duff's Device.
      Ответить

    Добавить комментарий