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

    +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
    /* https://habr.com/ru/company/piter/blog/491996/
    
    Пусть в Python такая штука и называется генератором, в языке C++ она
    называлась бы корутиной. Пример взят с этого сайта: https://masnun.com/2015/11/13/python-generators-coroutines-native-coroutines-and-async-await.html
    
    def generate_nums():
         num = 0
         while True:
              yield num
              num = num + 1	
    
    nums = generate_nums()
    	
    for x in nums:
         print(x)
    	
         if x > 9:
    */
    
    #include <stdio.h>
    #include <stdlib.h>
    #include <stdint.h>
    #include <stdbool.h>
    
    #define START 0
    #define YIELD 1
    
    typedef struct 
    {
      uint8_t jmpto;
      int num;
    } coroutine_state;
    
    
    int generate_nums(coroutine_state *state)
    {
      switch(state->jmpto)
      {
        case START: break;
        case YIELD: goto yield;
      }
      while (true)
      {
        state->jmpto = YIELD; return state->num; yield: // какая питушня
    
        state->num = state->num + 1;
      }
    }
    
    
    
    
    int main(void)
    {
      int x;
      coroutine_state st = {START, 0};
      while(true)
      {
        x = generate_nums(&st);
        printf("%d\n", x);
    
        if (x > 9)
        {
          break;
        }
      }
      return EXIT_SUCCESS;
    }

    Попробовал переписать эту ко-ко-корутину c питуха на Си - получилась какая-то херня нечитаемая. что еще раз доказывает, что корутины нахуй не нужны

    К тому же в крестопарашном говне они требуют хип, а это нахуй не нужно на самом-то деле.

    Запостил: j123123, 28 Сентября 2020

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

    • Собственно, эту функцию можно даже так пропатчить, поскольку "корутинный ретурн" тут только один
      int generate_nums(coroutine_state *state)
      {
        switch(state->jmpto)
        {
          case START: state->jmpto = YIELD; break;
          case YIELD: goto yield;
        }
        while (true)
        {
          return state->num; yield: // какая питушня
      
          state->num = state->num + 1;
        }
      }
      Ответить
      • #define YIELD(x) state->jmpto = __LINE__; return x; case __LINE__:
        Ответить
        • Блядь ебучие уиелд. Ненавижу его.
          Ненавижу потому читаю постоянно его "елда"
          Ответить
          • https://bg.wikipedia.org/wiki/Елда
            Ответить
            • Это же болгарский?
              Ответить
            • Елда может также означать:

              Елда — персонаж осетинского нартского эпоса, первая жена нартского богатыря Урузмага.
              Елда, или Ялда — женское имя иранского происхождения.
              Елда — просторечно-бранное слово, не относящееся к матерной лексике, обозначающее половой член.
              Ответить
    • > требуют хип

      Требуют аллокацию, а не хип.

      Ну и конпелятор вроде как имеет право не юзать хип, если ему очевидно, что корутина за пределы функции не вылетает.

      З.Ы. Один фиг это лучше чем context switch и новый стек под каждую корутину.
      Ответить
      • показать все, что скрытоvanished
        Ответить
        • Да, там всего одна аллокация. Но надо как-то угадать размер буфера.

          Там же одна из главных проблем крестов - по прототипу корутины невозможно понять сколько байт ей надо т.к. ты не видишь её локалки.

          А если конпелятор (1) доказал, что корутина юзается только внутри твоей функции, (2) видит полную реализацию, а не прототип, то он и сам не будет юзать аллокатор.
          Ответить
          • показать все, что скрытоvanished
            Ответить
            • Да там всё равно проблемы остаются. Корутина может звать другие корутины. И их состояние либо выделяется на куче либо эмбеддится в стейт вызывающей корутины.

              Т.е. тебе надо видеть не только локалки, но и полную реализацию всего говна, которое вызывает текущая корутина. И так далее.

              Как всегда всё упёрлось в паразитирование на сишном линкере. Так то размер буфера можно было бы посчитать во время компоновки. И заодно сделать в крестах нормальную инкапсуляцию, чтобы ты всегда мог выделить память под объект не видя его реализации. Но сишный линкер - это святое, его нельзя трогать, увы.
              Ответить
              • > Но сишный линкер - это святое, его нельзя трогать, увы.

                А то пишут, пишут... линкер, аллокации какие-то... Голова пухнет. Взять бы всё, да и засунуть в одну единицу трансляции.

                В крестах же принято в .h файлы всякое говно запихивать, так что можно и корутины там писать, и тупо их инклудить. Сделать как типа вариант инлайн функций
                Ответить
              • > Да там всё равно проблемы остаются. Корутина может звать другие корутины. И их состояние либо выделяется на куче либо эмбеддится в стейт вызывающей корутины.

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

                И такие ограниченные корутины вполне подошли б какими-нибудь байтоебам-эмбедщикам, только вот говностандартизаторы о них видимо думают в самую последнюю очередь.
                Ответить
                • > передать структуру

                  Ну т.е. по сути сделать корутину классом, а не функцией. Тогда ты сам создаёшь её инстанс где тебе удобно - хоть на стеке, хоть в статике, хоть внутри другой структуры. Вроде норм. Странно, почему они решили именно функции косплеить.
                  Ответить
            • Хотя всё ещё хуже. Корутины маскируются под обычные функции, ничто не мешает мне взять указатель и передать куда-то. А там уже позвать, зная только прототип.

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

      Здесь сразу становится понятно - почему С++ развивается в сторону языка-кодогенератора. Статический язык - это язык высшего порядка - это мета-язык. Человек не должен писать код. В какой-то степени это понимают запартыши и какие-то потуги в этом направлении у них ведутся, но всё это бесполезно. Это примитивная, бездарная херня, которая никому не нужна. Как-нибудь я подробней об этом(о запарте и почему она обречена) расскажу.

      На самом деле, открою тайну, но сишка так же является скриптухой. Правда с одним нюансом. Из-за того, что там ничего нет - там никакие проблемы особо не проявляются. Потому как любой код на сишке - это мономорфная кодогенерация(ручная). Т.е. используя сишку - мы просто в 90% времени делаем обезьянью работу.

      И здесь так же можно понять - почему я всегда хейтил и хейчу C++. Си с классами - это чистая скриптуха. Уже полиморфная. А вот C++ как мета-язык не состоятелен. Что мы хотим от мета-языка? Мы хотим, чтобы он производил то, что мы можем произвести руками(с теми же, либо лучшими свойствами). Но он не производил. И вот только с gnu++2a - язык стал в какой-то мере полноценным и позволяет заменить си.
      Ответить

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