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

    −3

    1. 1
    2. 2
    3. 3
    4. 4
    void print_line(char *s){
        for(int i = 0; i < strlen(s); i++) putchar(s[i]);
        putchar('\n');
    }

    Почему C работает медленнее чем JavaScript ?

    Запостил: o8603054, 17 Января 2019

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

    • Поскольку char * не хранит длину строки и её нужно каждый раз получать, сканируя всю строку на предмет байта '\0', выполнение функции strlen требует времени O(n), где n –— длина строки.

      Цикл for в Си не кэширует условия (в отличие от Паскаля, например, где границы индекса определяются один раз), поэтому будет вызывать strlen на каждой итерации.

      Итого сложность получится O(n²).

      Вот такой вариант быстрее:
      void print_line(char *s){
          int length = strlen(s);
          for(int i = 0; i < length; i++) putchar(s[i]);
          putchar('\n');
      }
      Ответить
      • А еще лучше так
        void print_line(const char *s) {
            for(int i = 0; s[i] != 0; i++) putchar(s[i]);
            putchar('\n');
        }
        Ответить
        • А ещё лучше юзать укозатели. Но всё равно, мне не нравится вызов в суслике. Раз уж си и лоу-левел лучше уж сразу скопировать в видеопамять или куда там ещё.
          Ответить
          • показать все, что скрытоvanished
            Ответить
            • А ещё чтобы была защита от захвата вывода myprogram.exe > dump.txt
              Ответить
              • показать все, что скрытоvanished
                Ответить
                • Кокококой кококод?
                  Ответить
                  • показать все, что скрытоvanished
                    Ответить
                    • Если приложение или ОС защищённого режима, то да. В VDM и в DPMI приходится реализовывать транслятор для каждой функции каждого прерывания (BIOS не сможет просто так разыменовать укококозатель на память защищённого режима).

                      Но именно это и позволяет досовскую программу запустить в окне (если бы это было не так, она бы пачкала своим выводом окна).
                      Ответить
                      • Да даже не в том дело биос не сможет разыментовать, тут ведь до биоса-то и не дойдет: обработчик прерываний ОС получит уведомление об INT, и не вызовет код биоса.

                        А даже если бы и вызвал, то в регистр сегментов надо загрузить адрес такой структуры где сказано что это сегмент 16битного кода, иначе процессор не сможет выполнить код биоса, ну тупо может быть invalid opcode.

                        А судя по "asm (" и "movw " (AT&T syntax) речь идет о каком-то unix-like.

                        Так что режим там сто пудово защищенный 32х битный.

                        Может быть это Xenix: там 16бит, но все равно защищенный (просто без виртуальной памяти)
                        Ответить
              • а если без шуток, то это надо через API tty делать: и ">" не сработает и поддержит все терминалы: и псевдотерминалы (ssh, xterm) и виртуальную консоль и даже физичеческий vt220 по гомпорту
                Ответить
          • void print_line(const char *s) {
                uint16_t sp = s;
                uint16_t len = strlen(s);
                asm (
                    "movw $0x1300, %%ax\n"
                    "movw %0, %%bp\n"
                    "movw %1, %%cx\n"
                    "movw $0, %%dx\n"
                    "movw $7, %%bx\n"
                    "int $0x10" :: "r"(s), "r"(len)
                );
            }
            Ответить
            • показать все, что скрытоvanished
              Ответить
            • А через прерывание 0x80 даже работать будет.
              Ответить
              • В "Solaris" или в "BSD" будет?
                Ответить
              • показать все, что скрытоvanished
                Ответить
                • Да, причём даже в 64-битной проге его можно дёрнуть. Но ABI там 32-битное, поэтому указатель хуй передашь.
                  Ответить
                • Запинал под 64 бита: https://ideone.com/nQgysb
                  Ответить
                  • Не совсем по-царски:
                    - const char* str = "Hello, world!\n";
                    + const char str[] = "Hello, world!\n";
                    - size_t len = strlen(str);
                    + size_t len = sizeof(str) - 1;

                    Теперь норм.
                    Ответить
                    • Не норм. Надо ещё mmap через прерывание звать. Но мне лень.
                      Ответить
                    • лишний байт!
                      char str[] = {'H', 'e', 'l','l'...};
                      size_t len = sizeof(str);
                      Ответить
                  • показать все, что скрытоvanished
                    Ответить
                    • А нафиг делать мув если конпелятор сам способен всё разложить куда надо? Зачем ему палки в колёса вставлять?
                      Ответить
                      • показать все, что скрытоvanished
                        Ответить
                        • Да, только %%eax.
                          Ответить
                          • Действительно, один знак процента во встроенном асме захватит макроподстановка, поэтому нужно удвоить.
                            Ответить
                        • Царь, кстати, был против вставления палок в колёса кокококонпелятору. Он знал, как кокококонкретная версия «gcc» всё раскладывает, поэтому его программы были заточены под кококококонкретную версию «gcc».

                          > movb $4, %eax сработает?
                          Ты хочешь в 32-битный регистр положить 8-битное число? Серьёзно? Или пиши movd, чтобы кокококонстанта была 32-битной, или используй movs/movz, расширяющие число (но они умеют расширять только в два раза: 8 бит до 16, 16 до 32, 32 до 64 и так далее).

                          Можно, кокококонечно, написать movb $4, %al и получить в трёх старших октетах мусор.
                          Ответить
                          • >>Ты хочешь в 32-битный регистр положить 8-битное число? Серьёзно?
                            ой я дурак-дурак, конечно я хотел movd это же дабл ворд на интеле.

                            А можно положидь туда нуль а потом положить в нижнюю половинку (al), но это конечно говнецо

                            хих, прикольно, я давно на асме не писал
                            Ответить
                            • Я ошибся, не -d, а -l.

                              • movl $, %eax займёт 5 байт.

                              • xor eax, eax + mov al, 4 (пишу в синтаксисе «Интела») займёт 2 + 2 = 4 байта (ещё и во флаги насрёт).

                              • lea eax, [4] займёт 6 байт (когда в квадратных скобках смещение без регистра, нужна 32-битная константа).

                              • Можно исхитриться и написать lea eax, [eax + 4], тогда она займёт 3 байта (смещение может быть 8-битным или 32-битным), но нужно обнулить eax (самый короткий способ сделать это займёт 2 байта). Итого xor eax, eax + lea eax, [eax + 4] займут 5 байт.

                              • Погуглил про movsx и movzx (давно ими не пользовался). Оказывается, можно 8 бит расширить сразу до 32, но работают они только с регистрами или с памятью.
                              Тогда mov al, 4 + movzx eax, ax займут 2 + 2 = 4 байта.
                              Ответить
                              • Есть ещё однобайтовые инструкции CBW (расширить AL до AX) и CWDE (расширить AX до EAX).

                                mov al, 4 + cbw + cwde займут 4 байта.
                                Ответить
                                • Зато по тактам однозначно проебут тупому пятибайтному муву...

                                  Сначала эти мелкие инструкции засрут декодер, а потом ещё и выстроятся в очередь друг за другом.
                                  Ответить
                                  • Ещё идея: в 64-битном режиме можно использовать rip-адресацию. Тогда нужный байт при хорошем стечении обстоятельств можно вытянуть из какой-нибудь соседней инструкции.
                                    Ответить
                  • В «Cygwin» и в «MSYS» кокококомпилируется, но не работает. Слой «POSIX» они сделали, а слой «Linux» не стали.
                    Ответить
                    • показать все, что скрытоvanished
                      Ответить
                    • а не
                      WSL тоже не будет

                      Лососисис тунцов
                      Real x86-64 Linux may or may not handle int 0x80 even in 64-bit process. That depends CONFIG_IA32_EMULATION of kernel config.
                      WSL is not.

                      https://github.com/Microsoft/WSL/issues/3107
                      Ответить
                    • Попробуй труъ 64-битную версию, которую я скинул чуть ниже. Возможно, что они только 64-битное ABI запилили.
                      Ответить
                • А вот с кошерным ABI: https://ideone.com/gqtUbq
                  Ответить
            • Питушня какая-то. Неужели нельзя включить O3/Release mode, чтобы ОП-код стал по скорости как жсный?
              Неужели даже просто до O(n) с неважно какой константой оптимизация не доводит?
              Ответить
          • а нука напомни мне адресс видеопамяти для nvidia видюх. а то X11 меня бесит хочу свои окошки :)
            Ответить
            • lspci > your_cheek.txt
              Ответить
            • показать все, что скрытоvanished
              Ответить
              • Вспомнил прикол из 90-х. Школьник, начитавшись журнала «Хакер», обращается к своему другу –— «компьютерному гению»:
                –— А можно перепрограммировать контроллер 13-го прерывания?
                Друг пытается понять, чего же от него хотят и что это за загадочный контроллер. Выдохнув, отвечает:
                —– Ну, допустим, можно. А тебе это зачем нужно?
                –— Винт отформатировать хочу! На низком уровне!
                Ответить
                • А кстати, Low Level Format работал на IDE? Мне казалось что там и команды-то такой не было уже, только в MFM. Вроде бы размер блока там был прибит гвоздями и равнялся 512 байтам чуть ли не до конца нулевых, когда появились большие блоки

                  Вот на флопаре он работал, но можно было и без биоса обойтись: обычный format.com это делал (и высокоуровневое и низкоуровневое), иначе как бы им можно было сменить размер дискеты?
                  Ответить
                  • 512 байт –— это только логический размер блока. На современных HDD интерфейса «ATA» физический блок простым смертным недоступен (он может весить несколько кило). В таких винчестерах по сути целый компьютер (ты помнишь про подключение в режиме терминала, муху цэцэ –— вот это всё). Как они транслируют логические адреса в физические, даже хуй не знает (точнее знают только инженеры производителя винчестеров).

                    В BIOS'ах конца 90-х была функция «Low Level Format», но на самом деле это была файка: она фактически тупо записывала нули во все логические блоки, т. е. это высокоуровневое форматирование, но без файловой системы.

                    На флопаре format.com выполнял не совсем низкоуровневое форматирование. Он не мог отформатировать сбойные дискеты или дискеты, которые до этого были неправильно отформатированы.

                    Настоящее низкоуровневое форматирование дискет выполняла программа «FDA» –— «floppy drive analyzer». Она умела читать межсекторные промежутки, записывать любые заголовки физических секторов. С помощью неё можно было отформатировать дискету не только для «IBM PC», но и для «ДВК», «Агата» –— вот этого всего зоопарка чудовищ. Вот эта программа могла творить чудеса.
                    Ответить
            • А ну-ка, давай-ка, плясать выходи!
              Ответить
              • Нет, concat_view, нет, concat_view, нет, concat_view, погоди!
                Ответить
                • Зарезал тебя на барбекю, пригласил своих знакомых осетинских гопников, пахнущих навозом, проверь.
                  Ответить
            • Ну как, узнал адрес?
              Ответить
      • А вот такой ещё быстрее:
        puts(s);
        Ответить
    • Чот ты поздно, обычно это в сентябре проходят
      Ответить
      • Это восьмой гость провоцирует нас на обсуждение лоу-левел говна. Он часто так делает.
        Ответить
    • показать все, что скрытоvanished
      Ответить
    • Ахуеть, петухи на сях кодят.
      Ответить

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