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

    +2

    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
    65. 65
    66. 66
    67. 67
    68. 68
    69. 69
    70. 70
    71. 71
    72. 72
    73. 73
    74. 74
    75. 75
    76. 76
    77. 77
    78. 78
    79. 79
    80. 80
    81. 81
    82. 82
    83. 83
    84. 84
    85. 85
    86. 86
    87. 87
    88. 88
    89. 89
    90. 90
    #include <stdio.h>
    #include <stdlib.h>
    #include <math.h>
    
    #define NUMARGS(type,...)  (sizeof((type[]){__VA_ARGS__})/sizeof(type))
    #define xDEF(type) typedef struct {size_t size; type* arr;  }  xARR(type)
    #define xARR(type) jArr_ ## type
    
    #define A(type, ...) (xARR(type)) {NUMARGS(type,__VA_ARGS__), (type[]){__VA_ARGS__}}
    
    #define _FOR(type, item, Arr) type item=Arr.arr[0]; for(size_t I = 0; I < Arr.size; item=Arr.arr[++I] ) 
    // MSVC
    #define xFOR(type, item, array) do{  _FOR(type, item, array) {
    // GCC, Clang
    #define FOR(item, array)        do{ __auto_type Arr=array; _FOR(__auto_type, item, Arr) {
        
    #define NEXT }} while(0);
    
    #define OfArray(type,arr) (xARR(type)){sizeof(arr)/sizeof(type), arr }
    
    typedef struct {
        char *name;
        int     id;
    } Entry;
    
    
    typedef struct {const char *name;} Str;
    typedef struct {int x[2]; } Pair;
    
    xDEF(Entry);
    xDEF(Str);
    xDEF(Pair);
    xDEF(int);
    
    void printEntry(xARR(Entry) entries)
    {
        xFOR(Entry, e, entries)
            printf("%s %d \n", e.name, e.id);
        NEXT
    }
    
    void printSquares(xARR(int) ints)
    {
        FOR(v, ints)
            printf("%d²=%d\n", v,(int) pow(v,2.));
        NEXT
    }
    
    int main(void)
    {
        xARR(Entry) e = A(Entry, {"one",1}, {"two",2}, {"three",3});
        printEntry(e);
        
        puts("_______________________________________");
        
        // можно передавать в метод непосредственно аргуметом
        printSquares( A(int, 3, 7, 5, 4) );
        puts("_______________________________________");    
        
        int nums[]={4,3,2,1};
        // можно использовать ранее объявленный массив
        printSquares(OfArray(int,nums));
        
        // можно итерироватьcя по ранее объявленному массиву
        FOR(i, OfArray(int, nums))
            printf("%d-",i);
        NEXT
        
        puts("\n_______________________________________");
        
        //вложенные циклы:
        for (int k=1;k<3;k++)
            FOR(i, A(Str, "kakoi", "bagor"))    
                FOR(j, A(int, 1111,2222,3333))
                    printf("%d %s %d\n", k, i.name, j);
                NEXT
            NEXT
        
        puts("_______________________________________");
        
        FOR(v, A(Pair, {1,2}, {11,12}, {20,21}))
            printf("%d,%d\n", v.x[0], v.x[1]);
        NEXT
        puts("_______________________________________");    
        //проблема пустого варарга
        FOR(j, A(int))
            printf("%d\n", j);
        NEXT    
        return(0);
    }

    https://godbolt.org/z/o9Tv9EvGx

    Довёл for~each до ума.

    Запостил: 3.14159265, 23 Июля 2022

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

    • https://gcc.godbolt.org/z/TPa7f4P9j
      Сделал слайсы как в std::span

      //C++ doesnt do bounds checking so do I.
      #define SLICE(count, span, expr)  ({auto ret=span; expr; ret.size=count; ret;})
      #define GET_FIRST(count, span)       SLICE(count, span,)
      #define GET_LAST( count, span)       SLICE(count, span, ret.arr+=ret.size-count)  
      #define GET_SUB(from, count, span)   SLICE(count, span, ret.arr+=from) 
      
      
      void printSquares(SPAN(int) ints)
      {
          FOR(v, ints)
              printf("%d²=%d\n", v,(int) pow(v,2.));
          NEXT
      }
      void first()
      {
          //slice first / last / subspan examples
          
          int nums[]={1,2,3,4,5,6,7,8};
          puts(" take first 3");    
          printSquares( GET_FIRST (3, AsSpan(int,nums) ));
          
          puts("\n take last 2");    
          printSquares( GET_LAST  (2, AsSpan(int,nums)) );
      
          puts("\n subspan: take 4 from 3");    
          printSquares( GET_SUB   (2, 4, AsSpan(int,nums) ) );
          puts("\n");    
      }
      Ответить
      • Кокое мокроёбство )))
        9/10.
        Ответить
        • > 9/10
          В общем вечер пятницы, ночь субботы. Решил ещё поработать напильником.

          Теперь можно мутировать массивspan в цикле.

          //by pointer
              FOR3(v, ints, &)
                  *v =  *v + 100;
              NEXT


          Бонусом поддерживается любая функция и каст
          //в принципе в func возможна любая функция, каст, взятие указателя
              // пример каста: автоконверсия типа
              FOR3(f, ints, (float))
                  printf("%f, ", f);
              NEXT    
          
          //int even(x){ return x % 2 == 0;}
              FOR3(e, ints, even)
                  printf("%d ", e);
              NEXT


          https://godbolt.org/z/anMYvooxn
          Ответить
          • И самое главное: теперь отлавливается что AsSpan и остальные макросы вызываются на массиве. И мы получаем ошибку компилятора, когда пытаемся вызвать его на указателе, где Сишкой неявно произведёна деградация (std::decay)
            void test(int arr[])
            {
                // decay of array. classical beginner mistake. 
                // -Wsizeof-pointer-div can help but novice ignore warnings
                // here compiler will stop with error
                
                // printSquares( AsSpan(int,arr) );    
                puts("\n");    
            }


            В Сишке есть тонкая грань между массивом и указателем, выражается она в том что на одном sizeof работает правильно, а на другом нет. Но я долгое время никак не мог её выразить в ошибку компилятора.

            Да, в гцц есть -Wsizeof-pointer-div. Но это ворнинг, который анскильные нубы игнорят, не читают. Потому хотелось именно жёсткую ошибку. Пока не заглянул в ядро.
            Магия тут в гццизме (не)совместимости типа массива и указателя на его начало
            __builtin_types_compatible_p(typeof(a), typeof(&(a)[0]))
            Ответить
            • Для MSVC вероятно можно заставить в коде трактовать ворнинг как ошибку.

              #ifdef _MSC_VER
                   #pragma warning( error : 26485 )
              #endif
              
              
              
              https://docs.microsoft.com/en-us/cpp/code-quality/c26485?view=msvc-170
              Ответить
            • >В Сишке есть тонкая грань между массивом и указателем, выражается она в том что на одном sizeof работает правильно, а на другом нет.


              sizeof для указателя совершенно верно работает: он возвращает размер указателя:)
              Ответить
      • Ко-ко-ко
        Ответить
    • Ко-ко-ко-ко-ко!

      Йеей! Мокросы!
      Ответить
    • В Си нет никакого "auto"
      (т.е. есть, но оно не делает то же, что в крестопараше, см. https://stackoverflow.com/questions/2192547/where-is-the-c-auto-keyword-used )
      Ответить
      • Ключевое слово "auto" можно накостылить через typeof() если что.

        #define ASSIGN_AUTO(var_name, value) typeof(value) var_name = value;

        хотя это гну экстеншен, впрочем как и "__auto_type"
        Ответить
        • Да, я уже указал что __auto_type только для GCC/Clang,
          А если это не гнусня, тогда придётся использовать xFOR, где нужно явно указать тип.

          Так работает и в MSVC (я проверил).

          Просто это несколько неэстетично, т.к. его придётся писать джважды для составных макросов.
          xFOR(int, i, OfArray(int, nums))
          Ответить
        • > хотя это гну экстеншен, впрочем как и "__auto_type"

          Правильное замечение.
          typeof предпочтительнее, поскольку он поддерживается в православном tcc
          А __auto_type там нет.

          https://bellard.org/tcc/tcc-doc.html#GNU-C-extensions

          Я лоханулся, потому что не знаю Сишки.
          Ответить
          • __auto_type это костылёчек чтобы типобезопасно макроёбить?
            Ответить
      • 1.8: What's the auto keyword good for?

        Declaring vehicles.
        Ответить
      • в си ауто это ненужное ключслово, говорящее о локальности пременной
        но она и так блин локальна по умолчанию


        в си не нужно auto, потому что там нет шоблонов

        auto завезли не чтобы заменять им char, а чтобы не выписывать значение для ридонли итератора по мапе
        Ответить
    • Перекат!
      Ответить
    • Какой анскилл )))
      Ответить
    • FOR operator is based on the possibility of confusion over
      the default value semantics of the new range-based for loop, whereas previous
      methods of looping over containers resulted in reference semantics. This was
      8 A. Parsai et al. noted previously by Stephan Lavavej [14]. In his standard proposal, he lists three problems with the most idiomatic-looking range-based for loop, for (auto elem : range), namely:
      – It might not compile - for example, unique ptr3 elements are not copyable.
      This is problematic both for users who won’t understand the resulting com-
      piler errors, and for users writing generic code that’ll happily compile until
      someone instantiates it for movable-only elements.

      – It might misbehave at runtime - for example, elem = val; will modify the
      copy, but not the original element in the range. Additionally, &elem will be
      invalidated after each iteration.

      – It might be inefficient - for example, unnecessarily copying std::string.
      From a mutation testing perspective, the second reason is the main motivation to create a mutation operator. In the case of a range-based for loop that
      modifies the elements of a container in-place, the correct and generic way to
      write it is for (auto&& elem : range). For all cases except for proxy objects
      and move-only ranges, for (auto& elem : range) works as well


      Какие-то &, &&, какие-то конструкторы копирующие, movable.

      В крестах всё так сложно и всё так запутанно
      Сиплюструп прав, а я виноват.

      https://arxiv.org/pdf/2004.04206.pdf
      Ответить
      • Наш дурдом голосует за Страуструпа.
        Страуструп — точно наш кандидат!
        Ответить
    • Остановите его кто-нибудь, он сейчас в Александреску со Степановым превратится, и потом напишет буст для няшной
      Ответить
      • Так уже есть Boost Preprocessor.
        Борманд именно на нём писал свой AES в Сишном компайлтайме.

        https://www.boost.org/doc/libs/1_79_0/libs/preprocessor/doc/index.html

        На самом деле сильно упрощает мракоёбство.
        Ответить
      • Это его укусил напившийся туалетной воды Билл Гейтс со своим макропасквилянтством в PSDK.
        Ответить
        • тебя каждый день торкает гейтс, если ты прогер. не стоило так неуважительно...
          Ответить

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