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

    +1

    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
    63. 63
    64. 64
    #include <stdio.h>
    #include <string.h>
    #include <stdlib.h>
    
    #define SQARESZ 3
    
    
    void rotateclockwise(char *ptra, size_t sz)
    {
        char (*a_ar)[sz] = (void *)ptra;
        char b_ar[sz][sz];
        for (size_t y = 0; y < sz; y++)
        {
            for (size_t x = 0; x < sz; x++)
            {
                b_ar[y][x] = a_ar[sz-1-x][y];
            }
        }
        memcpy(a_ar, b_ar, sz*sz);
    }
    
    void print_ar(char *ptra, size_t sz)
    {
        char (*a_ar)[sz] = (void *)ptra;
        for (size_t y = 0; y < sz; y++)
        {
            for (size_t x = 0; x < sz; x++)
            {
                printf("%i ", a_ar[y][x]);
            }
            printf("\n");
        }
    }
    
    int main()
    {
        char a[SQARESZ][SQARESZ] =
        {
          {1,2,3},
          {4,5,6},
          {7,8,9}
        };
        
        print_ar((char *)a, SQARESZ);
        printf("\n");
        rotateclockwise((char *)a, SQARESZ);
        
        print_ar((char *)a, SQARESZ);
        printf("\n");
        rotateclockwise((char *)a, SQARESZ);
        
        print_ar((char *)a, SQARESZ);
        printf("\n");
        rotateclockwise((char *)a, SQARESZ);
        
        print_ar((char *)a, SQARESZ);
        printf("\n");
        rotateclockwise((char *)a, SQARESZ);
        
        print_ar((char *)a, SQARESZ);
        printf("\n");
    
        return 0;
    }

    https://habr.com/post/317300/ В C++17 до сих пор нет нормальных многомерных массивов, которые были в Fortran начиная с Fortran 90

    > UPD от 2016-12-10 14:03. Посмотрел на этот коммент от @selgjos, поэкспериментировал с компилятором и понял, что с помощью C99 VLA всё-таки можно добиться нужного мне эффекта.
    > В общем, окей, в C есть нужные мне массивы. Как и в Fortran. А в C++ их по-прежнему нет.

    Запостил: j123123, 26 Декабря 2018

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

    • >Впрочем, нормальный метод работы с многомерными массивами всё-таки есть в C++. В Boost.MultiArray. Но это Boost, это не стандартная библиотека, а потому не засчитывается.
      Ответить
      • А еще можно самому наговнякать через арифметику указателей. И что?
        Ответить
        • Я конечно веб-макака, так что поправь меня, если я не прав - но разница между Boost, который кусками уходит в стандарт и "самому наговнякать через арифметику указателей" очевидна.
          Ответить
          • Boost это кусок блядского крестодерьма с говношаблонами и препроцессором, который еще и меняется от версии к версии, часто ломая при этом обратную совместимость. А если я сам что-то наговнякаю, я буду этот код прекрасно понимать и поддерживать
            Ответить
            • Автор статьи с названием "В C++17 до сих пор нет нормальных многомерных массивов.." позже признает, что "нормальный метод работы с многомерными массивами всё-таки есть в C++...".
              Ты или крестик сними или трусы надень. Не хочется писать костыли - есть Boost. Не хочется Boost и писать костыли - не знаю, на fortran пиши. Кто вообще сказал что многомерные массивы оттуда должны быть в стандарте.
              Ответить
              • Что значит "есть в C++"? Фраза "есть в какой-то там библиотеке" это не значит "есть в C++". Никто ведь не говорил, что в C++ это принципиально невозможно сделать каким-либо способом. Просто этого НЕТ В СТАНДАРТЕ
                Ответить
                • Чёрт, как же меня бесит эта питушня в программировании.
                  Люди не создавали время и не знают, что такое время. Это нормально.
                  Люди создали кучу языков программирования, но не знают, что такое язык программирования.
                  "Сделать что-то в языке", "сделать стандартными средствами", "сделать кратко и надёжно" и "сделать просто" - разные, порою не пересекающиеся вещи. И даже если вводить термины вроде "стандартная библиотека", "стандартный способ", окажется, что всё равно их никто не будет использовать потому, что они бесполезны.
                  Ответить
                  • У C++ стандартная библиотека специально создаётся с тем умыслом, чтобы ей было всем одинаково неудобно пользоваться. Как же убог std::chrono по сравнению с каким-нибудь abseil Time [1].

                    [1] https://abseil.io/docs/cpp/guides/time
                    Ответить
                    • Я вообще для времени (если мне нужна переносимость) пишу минимальную сишкообертку над платформозависимым говном (для винды и позиксов это будет GetSystemTimePreciseAsFileTime() и clock_gettime() соответственно). Вон в mingw-w64 есть уже такое
                      https://github.com/mirror/mingw-w64/blob/16151c441e89081fd398270bb888511ebef6fb35/mingw-w64-crt/misc/gettimeofday.c#L44

                      https://github.com/mirror/mingw-w64/blob/16151c441e89081fd398270bb888511ebef6fb35/mingw-w64-libraries/winpthreads/src/clock.c#L109
                      Ответить
                    • Скорее, вместо того, чтобы создаваться в качестве рабочего инструмента, она проектируется как выразительное средство: так, чтобы можно было максимально непонятно выёбываться: http://aras-p.info/blog/2018/12/28/Modern-C-Lamentations/ . Что-то вроде «Perl», только с умной рожей и на полном серьёзе.
                      Ответить
                • >Фраза "есть в какой-то там библиотеке" это не значит "есть в C++"
                  Спасибо, что объяснил. Я так понимаю, сетевого взаимодействия в тоже "Нет в С++"?
                  https://stackoverflow.com/questions/27126126/why-is-there-a-networking-library-proposal-for-c14-17
                  Ответить
                  • > сетевого взаимодействия в тоже "Нет в С++"?

                    Нет, что вы, мы только факториалы в компайл-тайме считаем.
                    Ответить
                  • > Спасибо, что объяснил. Я так понимаю, сетевого взаимодействия в тоже "Нет в С++"?

                    Естественно нет. Вот например если ты захочешь на "C++" написать под какую-нибудь нестандартную ОС, под которую сеть будет реализована через какую-то свою, особую, несовместимую ни с чем жопу, то тебе придется через эту жопу делать сетевое взаимодействие.
                    Ответить
            • Boost - не Windows, сам без спросу не обновится.
              А написать свой хороший контейнер - уже достаточно нетривиальная задача, чтобы не пользоваться полустандартной библиотекой.
              Ответить
          • Не нужна там никакая арифметика указателей. Простенький 2-д массив пишется строк в 10 (оборачиваешь std::vector с n*m элементами, переопределяешь операцию индексирования), произвольной размерности, известной во время компиляции — ну может строк в 20-30.
            Ответить
            • Ну да, только для этого мне надо что-то в что-то оборачивать, определять методы с этими перегрузками. В языке Си мне этого ничего делать не требуется.
              Ответить
              • > надо что-то в что-то оборачивать

                В языке C++ ты можешь легко написать функции, которые будут работать с произвольными типами данных, а не только с char. ну и про malloc() и free() тоже можно будет забыть, за временем жизни будет следить вектор.
                Ответить
                • Что самое интересное - вектор не умеет в realloc(). Там если через strace глянуть - будет выделен новый кусок, а старый освобожден
                  Ответить
                • > В языке C++ ты можешь легко написать функции, которые будут работать с произвольными типами данных, а не только с char.

                  https://dev.by/news/intervyu-s-krisom-kasperski-aka-mysch-h


                  — Как я понял, твой успех был отчасти в том, что все пытались найти общее универсальное решение и впоследствии увязали в нарастающей сложности. Ты же решил узкоспециализированную задачу, зато смог это сделать эффективно и быстро. Немного отвлекаясь от основной темы, здесь мы снова возвращаемся к любимому тобой спору вокруг назначения языков C и C++.

                  — Каждый конкретный язык определяет мышление, хотим мы того или нет. Так вот, постоянно сталкиваюсь, что «плюсовики» тяготеют к решениям в общем виде, в то время как «сишники» решают задачу в частном виде, что в разы быстрее.

                  Одну текущую задачу сначала показали «плюсовику», спросив, сколько займёт её решение. Он сказал: «Здесь нужно писать могучий движок. Короче говоря, это проект на полгода». Его коллега-«сишник» поинтересовался: «А зачем?» Ведь поставленная задача укладывается в сотню строк кода! Ответ был ошеломляющим: «Ну и что, мы так и будем по сотне строк кода писать для решения частных задач, каждый раз, как они возникают? Нетушки, задачи надо решать раз и навсегда!».

                  По моему глубокому личному убеждению, проблемы нужно решать по мере их возникновения. Писать программы на вырост с избыточным универсализмом нужно лишь очень хорошо предварительно подумав, ибо это из серии «Почему сегодня не делают корабли, летающие к звёздам?» Ответ прост: потому что корабль, построенный завтра, прибудет быстрее, а корабль, построенный послезавтра, еще быстрее. И их обоих обгонит корабль, построенный лет через пятьдесят, но когда он вернётся обратно, то обнаружит, что у человечества совсем другие проблемы».
                  Ответить
            • ... а чем не угодили "очевидные" варианты? например:

              * std::vector<std::vector<int>> (топорный вариант, проверено временем - работает ок-ish)

              * std::map< int, std::vector<int> > ( если часто надо переаллоцировать первый уровень )

              я в прошлом начал с первого, но закончил std::list<std::vector<int>>, потому что по первому индексу надо было только итерировать (прямое индексировние был не нужен), и надо было добавлять новые строки часто.

              на glibc под прыщами, аллокатор как-то хитрожопо соптимизирован, что существенной разницы по расходуемой памяти было почти невозможно померять. может только если размерности в тысячах/миллионах. но мне это было не надо.
              Ответить
              • > что существенной разницы по расходуемой памяти было почти невозможно померять

                Mежду чем и чем разницы? Между одним вектором и N векторами? Так она отличается только на примерно на ~3*N интов.

                Существенное отличие не в потреблении памяти, а в кол-ве обращений к аллокатору. Если ты создаёшь один вектор, у тебя будет ровно одна аллокация на всю матрицу. Если ты делаешь вектор/список/мапу векторов, у тебя будет N+1/2*N аллокаций (а в случае списка/мапы ещё и куча мелких объектов). Для числодробилок это может быть важно.

                Память лучше выделять редко и большими блоками.

                Если тебя устраивает list<vector>, то пирфоманс тебе явно не особо важен.
                Ответить
                • > а в кол-ве обращений к аллокатору.

                  в курсе. про это не написал - но точно также на линухе никакой существенной разницы не видел.

                  если конечно в tight loop впихнуть там будет сильно заметно.

                  но в приложении которое еще что-то делает - это капля в море.

                  честно говоря самого удивило. колличество аллокаций я поэтому и не мерял - потому что я видел что glibc/stdc++ какую-то магию творит уже на расходе памяти.

                  на старых системах/старых STL версиях я делал оптимизации std::map/list -> std::vector и видел 2-5х меньше расход памяти и 2х прирост производительности. тест аналогичного кода на линухе - разница была в пределах ошибки измерения.
                  Ответить
              • > ... а чем не угодили "очевидные" варианты? например:

                Как минимум тем, что у тебя эта хрень будет хуже кешироваться процессором из-за того, что аллокатор как попало может это дело разбросать. Да и операция взятия конкретного элемента из такого "двумерного массива" будет больше тактов проца жрать
                Ответить
                • Цитирую:

                  > В C++17 до сих пор нет нормальных многомерных массивов, которые были в Fortran начиная с Fortran 90

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

                  Все недостатки - и достоинтства - той или иной реализации массивов, как ты не крути, в независимости языка, будут присутствовать.

                  Если ты хочешь размерность массива в рантайм менять - ... со всеми вытекающими.
                  Если ты хочешь оптимальный кэш футпринт - ... со всеми вытекающими.
                  Если ты хочешь оптимальную прямую индексацию - ... со всеми вытекающими.

                  С/С++ тебе позволяет через библиотеку делать как тебе нравится.

                  На Фортране (и Пасцале, и Лиспе) уже в язык захардкожено.

                  Wähle Dein Gift.
                  Ответить
              • показать все, что скрытоБлядь, как всё сложно. Поэтому я за "PHP".
                Ответить
    • > VLA

      Правильно, чтобы ногу с корнем оторвало.
      Ответить
      • VLA там только для каста использовать можно, если что.
        Ответить
        • Да, посмотрел статью.

          А для чего код в топике? Там же во время компиляции все размеры известны, автор статьи другого хочет.
          Ответить
          • В этом примере да, но вообще та функция может тебе любой квадратик поворачивать по часовой. Это просто пример.
            Ответить
            • > char b_ar[sz][sz];
              вай вай

              К слову, на 90 градусов очень легко развернуть in-place: транспозиция + отражение дают поворот.

              Т.е. к примеру если транспонировать и отразить каждую строку, получишь поворот по часовой стрелке. Если отразить каждый столбец — против часовой стрелки.

              А теперь напиши функцию, которая будет вращать матрицу на произвольное кол-во элементов относительно центра.
              Ответить
    • В S" Forth" нет никаких массивов => в S" Forth" нет проблем с массивами.

      Именно поэтому я за S" Forth"
      Ответить
      • показать все, что скрытоvanished
        Ответить
        • Придумал на днях эзотерический язык, назвал его "". В нём всего один оператор —– "", он принимает один операнд. В результате применения этого оператора к самому себе мы можем получить "", применив оператор ещё раз получится "" и т.д. Вся программа на "" состоит из композиций оператора "" с оператором "". Вот пример программы:
          А вот интерпретатор этого языка написанный на нём же:
          Это единственный интерпретатор размером в 0 байт. И, как вы могли догадаться, все программы на этом языке занимают 0 байт. Соответственно, пися на этом языке мы существенно экономим память, да и вообще все ресурсы конпуктеров, а так же время и моск разработчика.
          Ответить
          • У меня есть идея куд-куд-куд-куда более эзотерического языка. Программы на нём имеют отрицательный размер. Способ хранения: берём текстовый файл с предсказуемым содержимым (например, с классической художественной литературой), отрезаем от конца N байт. Эти N байт, нигде не хранящиеся, и будут программой. «Сохранив» такую программу, мы уменьшили текстовый файл на N байт, значит, на диске программа весит -N байт.

            Пример. Возьмём исходный текст:
            Горные вершины
            Спят во тьме ночной;
            Тихие долины
            Полны свежей мглой;
            Не пылит дорога,
            Не дрожат листы...
            Подожди немного,
            Отдохнёшь и ты.

            Чтобы сохранить программу, состоящую из «Отдохнёшь и ты.», нужно отпилить от стихотворения последнюю строчку.

            Правда, я пока ещё не придумал, как будет интерпретироваться такая программа.
            Ответить
    • показать все, что скрыто
      * g o a t s e x * g o a t s e x * g o a t s e x *  
       g                                               g  
       o /     \             \            /    \       o  
       a|       |             \          |      |      a  
       t|       `.             |         |       :     t  
       s`        |             |        \|       |     s  
       e \       | /       /  \\\   --__ \\       :    e  
       x  \      \/   _--~~          ~--__| \     |    x  
       *   \      \_-~                    ~-_\    |    *  
       g    \_     \        _.--------.______\|   |    g  
       o      \     \______// _ ___ _ (_(__>  \   |    o  
       a       \   .  C ___)  ______ (_(____>  |  /    a  
       t       /\ |   C ____)/      \ (_____>  |_/     t  
       s      / /\|   C_____)       |  (___>   /  \    s  
       e     |   (   _C_____)\______/  // _/ /     \   e  
       x     |    \  |__   \\_________// (__/       |  x  
       *    | \    \____)   `----   --'             |  *  
       g    |  \_          ___\       /_          _/ | g  
       o   |              /    |     |  \            | o  
       a   |             |    /       \  \           | a  
       t   |          / /    |         |  \           |t  
       s   |         / /      \__/\___/    |          |s  
       e  |         / /        |    |       |         |e  
       x  |          |         |    |       |         |x  
       * g o a t s e x * g o a t s e x * g o a t s e x *
      Ответить

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