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

    +133

    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
    #include <stdlib.h>
    #include <stdio.h>
    #include <string.h>
    #include <unistd.h>
    
    void my_char_plus(const void *a, const void *b, void *c)
    {
      char tmp =  (*(char*)a + *(char*)b);
      memcpy(c,(void*)(&tmp),sizeof(char));
    }
    
    void my_char_minus(const void *a, const void *b, void *c)
    {
      char tmp =  (*(char*)a - *(char*)b);
      memcpy(c,(void*)(&tmp),sizeof(char));
    }
    
    
    
    void operation(const void *funct(const void*,const void*,void*),
                          const void *a, const void *b, void *c )
    {
      funct(a,b,c);
    }
    
    char ret_last_arg(const void *funct(const void*,const void*,void*),
                          const void *a, const void *b)
    {
      char c;
      funct(a,b,(void*)&c);
      return c;
    }
    
    
    
    int main(void)
    {
    
      char a, b;
      a = 5; b = 7;
      
      
      void *plus = &my_char_plus; char c;
      operation(plus, (const void*)&a, (const void*)&b, (void*)&c);
      printf("5 + 7 = %i\n", c);
      
      
      void *minus = &my_char_minus;
      char d = ret_last_arg(minus, (const void*)&a, (const void*)&b);
      printf("5 - 7 = %i\n", d);
      
      
    // LISP LISP LISP
    #define LISP(ar,aa,bb) ret_last_arg(ar, (const void*)&(char){aa}, (const void*)&(char){bb} )
    
      char e = LISP(plus,2,LISP(plus,2,2));
      printf("(+ 2 (+ 2 2 ) ) = %i\n", e);
      
      return 0;
    }

    Лиспопрограммирование на сишке через макрос (префиксная запись)
    Только оно кривовато тут, т.е. получаем трехадресный код (не как в лиспе)
    http://masters.donntu.edu.ua/2006/fvti/svyezhentsev/library/article2.htm
    Можно делать интерпретаторы фигни всякой, шитый код. Я упорот короче

    Запостил: j123123, 08 Мая 2014

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

    • Какой-то совсем неуниверсальный макрос - только 2 аргумента и только char в качестве результата (ну если мы цари - то 8, т.к. на x86_64 стековый фрейм все равно будет выровнен на 8).
      Ответить
    • Вот так уж тогда, если хочется префиксной записи:
      #define _(f, ...) f(__VA_ARGS__)
      _(printf, "%d\n", 42);
      Ответить
      • Ну, если у нас много аргументов и надо сложить... Флоаты, например. Флоаты это очень мерзкая ерунда, там даже результат сложения зависит от порядка операции. Т.е. в общем случае у нас ((a+b)+c) != (a+(b+c)) если все три - флоат. Трехадресный код это вроде как стандартное промежуточное представление для компиляторов. Например вот хорошая статья http://hal.archives-ouvertes.fr/docs/00/28/14/29/PDF/floating-point-article.pdf
        Ах да, тут еще царь на лоре активизировался, что-то про ассемблер и флоаты заговорил. Круто https://www.linux.org.ru/forum/development/10452829
        Ответить
        • > Ах да, тут еще царь на лоре активизировался
          Значит скоро к нам вернется, ждем с нетерпением.

          > Ну, если у нас много аргументов и надо сложить...
          То можно поюзать вариадик функцию. Кстати в лишпе + принимал сколько угодно аргументов, а не 2.

          > промежуточное представление
          Ну вот конкретно в этом коде получается не промежуточное представление, а тупо вычисление. Надо тогда макросом "компилить" в структурки с четырьмя полями (функция и три ссылки на ноды-аргументы), а не прямо в вызовы. Вот тогда будет интересней - можно будет и циклы мутить, и функции описывать прямо на этом метаязыке и т.п..

          К чему тут флоаты и их порядок - не понял.
          Ответить
          • Можно даже делать структурки не с 4 элементами, а с произвольным количеством (зачем ограничиваться трехаргументной формой со стороны программиста?). Примерно так:
            node * alloc_node(size_t n, func f, ...) {
                ...
            }
            
            #define _(f, ...) f(COUNT(__VA_ARGS__), f, __VA_ARGS__)
            Ответить
          • >К чему тут флоаты и их порядок - не понял.
            Сложение флоатов неассоциативно
            Ответить
            • А где я здесь нарушаю ассоциативность?
              Ответить
              • ( (0000000000000.1 + 0000000000000.1) + (0000000000000.1 + 0000000000000.1) ) + ( (0000000000000.1 + 0000000000000.1) + (0000000000000.1 + 0000000000000.1) )

                ( ( ( ( ( (0000000000000.1 + 0000000000000.1) + 0000000000000.1 ) + 0000000000000.1 ) + 0000000000000.1 ) +0000000000000.1 ) + 0000000000000.1 ) + 0000000000000.1

                Понятно?
                Ответить
                • Я знаю про проблемы с флоатами. Но где мой код нарушает порядок вычислений?
                  Ответить
                  • Какой порядок правильный? Сложение ведь коммутативно, ассоциативно
                    Ответить
                    • > Какой порядок правильный?
                      Если программист не указывает его явным образом (например скобками) - вообще любой. И ничто не мешает ему написать _(plus, a, _(plus, b, _(plus, c, d))), если его волнует эта проблема. Ну и в конце концов ты можешь написать, что многоаргументный plus всегда складывает флоаты слева направо, раз уж хочется определенности.

                      P.S. Я так и не понял, какое отношение флоатопроблемы имеют к этому треду. Поясни.
                      Ответить
                      • Макрос твой, он может и флоаты принимать, нет типобезопасности.
                        Ответить
                        • Ты про #define _(f, ...) f(__VA_ARGS__)?

                          Так этот макрос сам по себе ничего не принимает. Он только форвардит все аргументы функции f. А там уже компилятор сам проверит - можно ли ей их передать, и как она относится к данному количеству аргументов.

                          Естественно, что динамическая типизация работать не будет, и если функция принимает 2 инта, а ей отдашь 2 флоата - компилятор их тупо округлит.
                          Ответить
                          • >А там уже компилятор сам проверит - можно ли ей их передать
                            В чистом Си — слабая типизация
                            Ответить
                          • Статическая слабая типизация
                            Ответить
                          • Статическая слабая явная типизация Кто больше?
                            Ответить
                • Точки не там поставил, не скомпилится.
                  Ответить
              • http://www.yur.ru/science/computer/IEEE754.htm
                Ответить

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