1. Си / Говнокод #23318

    −16

    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
    22. 22
    23. 23
    24. 24
    25. 25
    26. 26
    27. 27
    28. 28
    29. 29
    30. 30
    31. 31
    32. 32
    33. 33
    34. 34
    35. 35
    36. 36
    37. 37
    38. 38
    39. 39
    40. 40
    41. 41
    42. 42
    43. 43
    44. 44
    45. 45
    46. 46
    47. 47
    48. 48
    49. 49
    50. 50
    51. 51
    52. 52
    53. 53
    54. 54
    55. 55
    56. 56
    57. 57
    58. 58
    59. 59
    60. 60
    61. 61
    62. 62
    char *cat2(char *str1, char *str2)
    {
      int len;
      char *ret;
    
      /* malloc new string */
      len = strlen(str1) + strlen(str2) + 1;
      ret = (char *) malloc(len*sizeof(char));
    
      /* copy the strings */
      strcpy(ret, str1);
      strcat(ret, str2);
    
      /* free old strings */
      free(str1);
      free(str2);
    
      return ret;
    }
    
    char *cat3(char *str1, char *str2, char *str3)
    {
      return cat2(cat2(str1, str2), str3);
    }
    
    char *cat4(char *str1, char *str2, char *str3, char *str4)
    {
      return cat2(cat2(str1, str2), cat2(str3, str4));
    }
    
    char *cat5(char *str1, char *str2, char *str3, char *str4,
    	   char *str5)
    {
      return cat3(cat2(str1, str2), cat2(str3, str4), str5);
    }
    
    char *cat6(char *str1, char *str2, char *str3, char *str4,
    	   char *str5, char *str6)
    {
      return cat3(cat2(str1, str2), cat2(str3, str4), cat2(str5, str6));
    }
    
    char *cat7(char *str1, char *str2, char *str3, char *str4,
    	   char *str5, char *str6, char *str7)
    {
      return cat4(cat2(str1, str2), cat2(str3, str4), cat2(str5, str6), str7);
    }
    
    char *cat8(char *str1, char *str2, char *str3, char *str4,
    	   char *str5, char *str6, char *str7, char *str8)
    {
      return cat4(cat2(str1, str2), cat2(str3, str4),
    	      cat2(str5, str6), cat2(str7, str8));
    }
    
    char *cat9(char *str1, char *str2, char *str3, char *str4,
    	   char *str5, char *str6, char *str7, char *str8,
    	   char *str9)
    {
      return cat5(cat2(str1, str2), cat2(str3, str4), cat2(str5, str6),
    	      cat2(str7, str8), str9);
    }

    Запостил: d_fomenok, 31 Августа 2017

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

    • а sprintf то чем не угодил?
      Ответить
    • А в языке с метушнёй эту задачу можно было бы решить один раз для всех моноидов.
      Ответить
      • Покажите пример решения.
        Ответить
        • Я как-то навалил возведение в степень в сишке, которое параметризуется через маросы (govno template library), но теперь упорно не могу найти его ни в гугле, ни в яндексе. Наверное, боты утопили.
          Ответить
          • > не могу найти его ни в гугле, ни в яндексе
            Ты его уже и там и там закоммитить успел?
            Ответить
            • > уже и там и там закоммитить успел
              Когда я говорю, что моноиды повсюду, я именно это имею ввиду
              Ответить
    • > можно было бы решить...
      решена* - + / + ... / accumulate
      Ответить
    • Говно в strcpy, т.к. "returns a copy of dest". Srly? а головой подумать нельзя было, перед тем, как стандарт писать?
      Ответить
      • То ли дело Кубасик:
        FUNCTION cat2(str1 AS STRING, str2 AS STRING) AS STRING
          cat2 = str1 + str2
        END FUNCTION


        А вообще у сишечки функции для строк запутанные. Ну вот зачем функция возвращает значение одного из аргументов?
        Ответить
    • Код писался какой-то анскилляброй заедушной. Во-первых, есть realloc. Во-вторых, вот эта вот хуита:
      char *cat3(char *str1, char *str2, char *str3)
      {
        return cat2(cat2(str1, str2), str3);
      }

      И вот типа тут вызывается cat2 который нам тут блядь аллоцирует массив размером в две строки, копирует две строки в него, освобождает память тех двух строк, ну а потом опять вызывается cat2 который ту же питушню делает. Царь разумеется выделил бы в cat3 память сразу под сумму размеров трех строк, и туда б эти три говностроки закопировали бы. А не вызывал бы cat2 два раза.
      НО Царь бы не стал использовать заедушно-анскильные сишные говнонультерминированные строки, а сделал бы паскалеподобные строки, потому как тогда можно четко и дерзко memcpy делать, а не анскилльно выяснять место нулевого байтика и потом копировать
      Ответить
      • Паскалевские цари придумали отличную реализацию строк, подходящую аж для целых 10% возможных случаев.

        МС цари придумали говнонедонультерминированные строки, они называются bstr и они говно потому что нет никакого способа воспользоваться bstr не выделяя память в куче и не прибегая к небезопасным костыльным хакам
        Ответить
        • Шаблонной магией разве не получится сформировать BSTR на стеке?
          Ответить
          • https://wandbox.org/permlink/8CvCZdtiInq6hM7n
            получится. Я это и имел в виду под "небезопасными костыльными хаками".

            И есть нюанс: компилятор вправе оптимизировать поле _size. А volatile использовать нельзя, т.к. это нарушает требования к constexpr

            Макроснёй даже проще.
            Ответить
        • А какая реализация строк подходит для 90% случаев, но при этом не требует небезопасных костыльных хаков и не требует сканировать всю строку каждый раз, чтобы определить длину?
          Ответить
          • На мой взгляд, идеальная строковая реализация должна соответствовать следующим требованиям (буду излагать в терминах с++, но в целом подходит и для других яп):
            1. кодировка по умолчанию - utf-8. Раздельные методы length (число символьных позиций) и size (размер в байтах). Явное указание кодировки в стандарте необходимо, иначе MS в своей реализации засунут туда локальную кодировку и сделают класс неюзабельным.
            2. sso, cow оптимизации
            3. API примерно как у QString, но с некоторыми изменениями:
            а. отсутствие дублирования, например: с empty(), но без isEmpty()
            б. преобразования кодировок - внешними параметризуемыми функциями
            в. две версии split - одна "засовывает" разбитые строки в существующий контейнер строк (vector<string> v; s.split('\n', v);) или возвращающий контейнер указанного типа (s.split<list>() -> list<string>)
            4. constexpr - конструкторы и базовые операции типа конкатенации (этого даже в с++17 для коротких строк не сделаешь)
            5. полностью параметризуемые числовые преобразования to/from для (хотя бы) числовых типов ("полностью" значит и система исчисления, и ширина позиции, и точность, и числоденежнолокальный формат)
            6. наличие соответствующего string_view со всеми аналогичными методами

            Сдается мне, таких строк нет ни в одном яп. А жаль.
            Ответить
            • п.с. и еще одно: throw/nothrow версии для методов конвертации.
              Ответить
            • > cow
              ненужно

              > QString
              ненужно

              > s.split<list>()
              ненужно

              > constexpr
              ненужно

              > числовые преобразования to/from
              ненужно
              Ответить
              • если убрать всё это "ненужное" мы получаем std::string в utf-8 с раздельными length/size. Пользоваться которым в повседневной разработке жутко неудобно
                Ответить
                • А мне std::string норм. А все, что я отметил - ненужно.
                  Ответить
                  • напиши парсинг, скажем, ip-адреса через api std::string
                    Ответить
                    • Я же не такой ущербный, чтобы ограничивать себя методами строки. Но парсинг строк сплитами и файндами - это не лучший способ. Сойдет только в качестве одноразового костыля.

                      boost::asio::ip::address_v4::from_string(s);
                      Ответить
                      • это может быть не IP, а какой-нибудь NMEA, под который библиотеки буста нет. API строк должен быть удобным и точка. А то получится как у Кнута:

                        http://franklinchen.com/blog/2011/12/08/revisiting-knuth-and-mcilroys-word-count-programs/
                        Ответить
                        • Как будто я спорю с тем, что апи должен быть удобным. Только у тебя получается плохо. Вон Роман ниже сказал, каким должен быть нормальный сплит.
                          И да, если при проектировании апи ты руководствуешься желанием писать наколеночные говнопарсеры, то ты делаешь это неправильно, как говорится.
                          Ответить
                          • апи должен позволять писать "наколеночные говнопарсеры", надо тебе оно или нет. Хотя помнится я достаточых NMEA-парсеров не находил
                            Ответить
                            • > апи должен позволять писать "наколеночные говнопарсеры"
                              Лол, нет. Строки - это строки, а парсеры - это парсеры, не надо их лепить в одну кучу.

                              Насчет утилит для работы со строками: я нигде не говорил, что они ненужны. Мне не понравились твои конкретные идеи (которые процитировал). Заметь, я назвал ненужным только один из двух предложенных тобой сплитов.
                              Ответить
            • > 1. кодировка по умолчанию - utf-8. Раздельные методы length (число символьных позиций) и size (размер в байтах)

              Итерация по символам где? Разбиение по словам и предложениям тоже неплохо иметь. Размера надо три: длину в байтах, в код поинтах и в графических символах.

              > возвращающий контейнер указанного типа (s.split<list>() -> list<string>)
              И зачем? Нужна ровно одна версия — которая range возвращает.

              > cow оптимизации
              Вот только не надо опять этот шлак тащить


              Кмк, нужны только годные классы с честными именами bytes и bytes_view, которые не притворяются строками (у них всё равно плохо получается). Они только управляют временем жизни и предоставляю апи для работы с байтами.

              Декодинг/подсчёт кодпоинтов/итерация и т.п. должны быть внешними функциями и возвращать ranges, которые можно засунуть в любой контейнер.
              Ответить
              • > Размера надо три: длину в байтах, в код поинтах и в графических символах.

                Я предлагаю в кодпоинтах. Для utf-8 это то же, что и в байтах. Обычно взять длину utf16 в байтах надо редко и для байтоебли, которую бы по возможности обойти. На крайняк на sizeof домножить

                с ranges интереснее. Если глянуть ranges v3, то для какого-нибудь (s1+s2) | split('\n') нужно будет делать to_vector/to_list. Вообще штука хорошая, но имо, с ucs была бы намного приятнее.

                Для строк нужно много того, чего не надо в других контейнерах. Те же кодпоинты например. Поэтому лучше пусть строки будут отдельно.

                Моя б воля, я б вообще malloc/free и всю другую аллокационную дрянь свел в вектор байт. Что - то типа bytes(a,15) = bytes(b, 15, 7) - скопировать 15 байт из b со смещением 7 в a
                Ответить
                • > Я предлагаю в кодпоинтах. Для utf-8 это то же, что и в байтах

                  Я вообще не понимаю, что ты имеешь в виду. Длина в байтах нужна всегда, определённо. Длина в кодпоинтах это совсем другое — сколько кодпоинтов можно декодировать из байтов (это тоже самое только для ASCII).
                  Третья длина — эта ширина строки в символах. Это не тоже самое, что ширина в кодпоинтах. Без нормализации диакритические знаки могут давать дополнительные кодпоинты, но при отрисовке всё сливается в один символ. Есть символы-пробелы нулевой ширины, а уж про хитрости арабского я вообще молчу, ибо знаком с темой очень поверхностно и могу только представить масштаб проблемы. Эмодзи — это отдельная боль, несколько значков эмодзи могут объединяться, образуя новый значок.

                  Всё становится совсем интересным, когда в строке смешиваются left-to-right и right-to-left.
                  Ответить
                  • число байт это число кодпоинтов * число байт в символе (это размер мы знаем)
                    Ответить
                    • Ну ты наркоман. Загугли, что такое кодпойнт.
                      Ответить
                    • Рассмотрим жуткие примеры:
                      1. Символ «F» в UTF-8 кодируется одним байтом, символ «Щ» — двумя. Чему равен размер кодпоинта?

                      2. Символы «F» и «Щ» в UTF-16 кодируются двумя байтами, некоторые китайские иероглифы — двумя парами, т. е. четырьмя байтами (google: суррогаты). Чему равен размер кодпоинта?

                      3. Символ «ё» можно записать одним кодом, а можно двумя: «е» + надстрочный акцент, состоящий из двух точек. Чему равен размер кодпоинта в обоих случаях?

                      4. Код «fi» имеет семантическое значение, как у сочетания букв «f» + «i».

                      Чтобы не запутаться, нам придётся разделить кодирование (байтовое представление типа UTF-8, UTF-16, UCS-2, UCS-4 etc.), графическое представление (количество знакомест, например) и семантику (эквивалентность сочетаний букв и сочетаний кодов).
                      Ответить
                      • Пункты 3 и 4 - это точно про кодпойнты? Я думал, "е" и акцент - это два юникодных кодпойнта. Когда несколько кодпойнтов кодируют один символ - это уже следующий уровень геморроя.
                        Ответить
                      • нет чего по делу сказать - привязались к тому, что я пару терминов перепутал, какой негодяй.
                        Ответить
                        • Я сам путаюсь в терминологии. Понадеялся, что кто-нибудь поможет распутать узелок...
                          Ответить
                  • И четвёртая и пятая длины - это ширина строки в пикселях и в клеточках для терминала соответственно. Но в стандартной либе ими можно пренебречь.
                    Ответить
                  • > Без нормализации диакритические знаки могут давать дополнительные кодпоинты
                    вон в компании эппл, например, считают, что буква й после нормализации (normalized to Apple-modifiedᵍᵃʸ variant of Unicodeᵀᴹ Normalization Format D) должна записаться в двух кодпойнтах "и"+"крышечка", и ниибёт
                    Ответить
                    • Может быть, проще будет normalized to Apple-modifiedᵍᵃʸ variant of Unicodeᵀᴹ Normalization Format D называть словом “denaturalization”? А то что-то слишком длинно получается.
                      Ответить
                  • > когда в строке смешиваются left-to-right и right-to-left.

                    Я как-то видел CSV файл с арабскими строками. Это вынос мозга.
                    Ответить
              • > И зачем? Нужна ровно одна версия — которая range возвращает.

                > Кмк, нужны только годные классы с честными именами bytes и bytes_view, которые не притворяются строками (у них всё равно плохо получается). Они только управляют временем жизни и предоставляю апи для работы с байтами.

                > Декодинг/подсчёт кодпоинтов/итерация и т.п. должны быть внешними функциями и возвращать ranges, которые можно засунуть в любой контейнер.

                Всё это можно вылечить через uniform call syntax.
                Ответить
            • > На мой взгляд, идеальная строковая реализация должна соответствовать следующим требованиям

              На мой взгляд, идеальной строковой реализации нет и быть не может. Может быть строковая реализация, хорошо подходящая под некие конкретные требования. Цари вообще никакими строками с кодировками пользоваться не будут, они сделают себе структуру под массив как в поцкале:
              struct tzar_str {
                size_t length;
                char data[];
              };

              и будут делать realloc, malloc и прочую хуиту руками, т.е. если царю надо где-то сконкатенировать семь таких строк, он может написать код, который вот берет от всех этих семи штук lenght, складывает, потом realloc-нуть первую строку по данному размеру и туда отmemcpy-ить все прочие, ну а если например царю надо будет много где в коде сшивать 7 строк в одну, царь, так уж и быть напишет функцию strcat7(struct tzar_str **a1, struct tzar_str *a2, ...) . И еще царь может накодогенерировать таких функций какие ему нужны для конкатенации нужных строк. Строка ведь по-сути это массив сраных байтов, нахера нужны эти ваши кривые абстракции со всякой херней?
              Ответить
              • кодировка может быть заложена в тип строки
                Ответить
                • Кодировку не надо закладывать, она может быть любая. При условии, что это UTF-8.
                  Ответить
                • А давайте подумаем, в каких конкретно функциях важна кодировка. А нужна она в следующих случаях:

                  1. В функциях регистронезависимого сравнения и поиска, в функциях изменения регистра — везде, где нужно определять/изменять регистр.

                  2. В функциях определения длины в знакоместах или в пикселях — там, где требуется информация о глифах, связанных с каждым символом.

                  3. В функциях вывода в консоль/гуй/файл, чтобы вывести поток в требуемой кодировке, а не Àíîíèìíûå.

                  4. В функциях определения длины в графических символах, в функциях вырезания фрагмента по графическим символам (вообще в функциях парсинга) — везде, где нужен доступ к графическому/семантическому символу, если кодировка переменной разрядности (как UTF-8).

                  *****

                  А теперь попробуем разделить на уровни:

                  1. Уровень хранилища. Строка — это просто цепочка байтов (пофигу в какой кодировке). Доступны функции выделения памяти, конкатенации, определения размера в байтах. Возможно, даже функции вывода (если предварительно чем-нибудь готовить нужную кодировку).

                  2. Уровень «зожатия». На этом уровне строка — это не просто цепочка байтов, а уже цепочка символов (но мы не знаем, на каком языке текст). В этот уровень заложен алгоритм упаковки кодпоинтов в байты, например, UTF-8, UTF-16 etc. На этом уровне доступны функции определения длины в кодпоинтах, функции вырезания фрагмента по номеру кодпоинта, функции чёткого поиска (поиск будет по кодпоинту, а не по символу) и сравнения.

                  3. Уровень символов. Строка на этом уровне — это цепочка конкретных известных символов. На этом уровне должна быть известна кодировка. На этом уровне доступны все функции парсинга (нечёткий поиск и нечёткое сравнение, например, регистронезависимое), функции изменения регистра, функции определения длины в знакоместах или в графических символах (да в чём угодно).

                  Третий уровень вообще может быть отдельной библиотекой.
                  Ответить
                  • еще есть функции преобразования кодировок

                    Моя идея: вот есть у нас набор классов codepage, с определенным набором методов, поведение которых зависит от кодировки. Например, преобразования регистра, поиск, преобразования кодировки - не принципиально. Есть дефолтный вариант:
                    using string = basic_string<char, codepage_utf8, allocator<...>>;

                    Скажем, для utf16:
                    using string_utf16 = basic_string<wchar_t, codepage_utf16, allocator<...>>;

                    Тогда преобразование кодировки:
                    string_utf16 s1 = u"какая-нибудь строчка";
                    string s2 = s1; // здесь вызовется какой-нибудь codepage_utf16::convert<codepage_utf8>(. ..);

                    Тогда а: добавление поддержки кодировки это всего лишь добавление библиотечного codepage_... класса
                    б. внутри яп кодировки уже не перепутаешь
                    Ответить
                    • а если кодировка определяется в рантайме?

                      Объекты кодировок нужны (и это уже реализовано в java, к примеру), а вот совать их в строки — сомнительная идея. Кмк, лучше, если все строки внутри языка в одной кодировке, а альтернативные кодировки используются для ввода/вывода.
                      Ответить
                      • codepage_runtime, вестимо. Там уже будет dispatch по поддерживаемым кодировкам. Просто в отличие от других codepage, codepage_runtime будет не нулевого размера, а содержать номер поддерживаемой кодировки
                        Ответить
              • > массив сраных байтов
                Плюсану. Имхо, все функции типа сравнений, поиска, нормализации, сплитов и т.п. должны быть внешними, а не торчать из строки.
                Ответить
                • > Имхо, все функции типа сравнений, поиска, нормализации, сплитов и т.п. должны быть внешними, а не торчать из строки.

                  >> Кмк, нужны только годные классы с честными именами bytes и bytes_view, которые не притворяются строками
                  >> Декодинг/подсчёт кодпоинтов/итерация и т.п. должны быть внешними функциями

                  Ну вот, нас уже трое. Осталось убедить комитетъ.
                  Ответить
                • когда строка это просто "массив сраных байтов" одно неверное движение превращает превращает текст в кракозябры. Например, windows возвращает текст ошибок HRESULT в системной кодировке и на системном языке. GL/HF, как говорится.

                  Что до внешних/внутренних функций - тут я надеюсь на uniform call syntax. С одной стороны, у строки нет метода (скажем) string::split(regexp r), зато в модуле/библиотеке regexp есть метод split(string &s, regexp r). И тогда можно писать return s.split(regexp("\d{1,}")).filter(regexp( "{*}")).join('\n');
                  Ответить
                  • > Например, windows возвращает текст ошибок HRESULT в системной кодировке и на системном языке

                    Напиши обёртку, которая возвращает строку в utf8.

                    > тут я надеюсь на uniform call syntax.

                    Это всё свистоперделки, сути не меняет.
                    Ответить

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