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

    +5

    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
    // Heap memory allocate function (must not be used!)
    caddr_t _sbrk(int incr) {
        <...>
        void some_bastard_called_sbrk();
        some_bastard_called_sbrk(); // Produce linker error in case it is used
    }
    
    _ATTRIBUTE ((__format__ (__printf__, 1, 2)))
    int	printf (const char *__restrict format, ...)
    {
        <маленький трехколесный велосипед>
    }
    
    int	putchar(int c) 
    {
        <...> 
    }
    int	puts(const char *s) 
    {
        <...> 
    }
    
    _ATTRIBUTE ((__format__ (__printf__, 2, 3)))
    int	sprintf (char *__restrict s, const char *__restrict format, ...)
    {
        <...> 
    }

    STM32. Я просто хочу использовать printf для вывода в последовательный порт и не течь. Ведь для этого нужно только реализовать int _write(int file, char *data, int len) и всё. Ой, а почему иногда программа падает где-то в кишках рантайма?

    Может, стек переполняется? Да нет, проверил, значения в норме...

    Просто стандартная библиотека от ST - это не курсовая ардуинщика, тут все системно, хендлы потоков, дескрипторы устройств и управляющие структуры. При первом обращении printf (и sprintf тоже!) выделяет себе в куче около 400 байт. Замечательное решение, помогающее сэкономить память, если мы не используем стандартный вывод! А куча тут - это просто последовательно заполняемая область памяти, размеры которой задаются в linker script (я вообще 0 указал, я ведь не использую malloc). Проверять выход за пределы кучи мы, конечно, не будем - зачем, когда рядом такая замечательная, никому не нужная область стека.
    Да, и если забыть отключить буферизацию setvbuf(stdin/stdout/stderr, NULL, _IONBF, 0); , то он выделит не 400 байт, а килобайт (на контроллере с 8K RAM).

    В общем, ах, оставьте меня, сам все напишу.
    Только надо еще putchar и puts реализовать, а то компилятор любит printf'ы оптимизировать. И не забыть, что puts добавляет перевод строки. Уф, вроде все.

    Запостил: Steve_Brown, 05 Августа 2022

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

    • > Да, и если забыть отключить буферизацию setvbuf(stdin/stdout/stderr, NULL, _IONBF, 0); , то он выделит не 400 байт, а килобайт (на контроллере с 8K RAM).

      Можешь использовать dprintf, ему никакой "FILE *" с "stdout" не нужен, только "int" с "STDOUT_FILENO"
      int dprintf(int fd, const char *format, ...)
      Ответить
      • Да там даже sprintf что-то себе выделяет, думаю, один хрен бы было.

        EDIT: Ну да: undefined reference to `some_bastard_called_sbrk'
        Ответить
    • показать все, что скрытотесновато у вас там)

      sbrk вроде и правда не нужен, нужно ммапить в кучу

      А вместо машинерии printf можно срать сисколом прямо в stdout (итебе еще повезло что там С++ с cout нет)



      зы: циферки вон уже принес расщирение позиксовое, которое реализует сёмантику printf, но без CRT а поверх прямо голово write
      Ответить
      • показать все, что скрыто> ммапить

        На контроллере без MMU?
        Ответить
        • показать все, что скрытоу меня в неконтролеррах все это есть


          без мму бркают наверное. Ну типа вот у нас есть память, вот отсюда до сюда стек, потом брк, потом хип. Брк туда сюда двигают, и текут

          так?
          Ответить
          • показать все, что скрытоЗачем там вообще бырк. Выделяешь в линкер-скрипте (или даже сишке) статичный регион под кучу и течёшь.
            Ответить
            • показать все, что скрытоЭто надо зараннеее знать!

              а так можно динамически в рантайме выбирать, что под стек что под кучу
              Ответить
              • показать все, что скрыто> динамически в рантайме выбирать

                Какая надёжность )))

                З.Ы. Это тебе не интел, там у стека ограничителей обычно нету. Разве что через MPU навертеть, но он не везде есть.
                Ответить
                • Ну, какая уж тебе надежность, если статус твоего тела (жив/не жив) является всего-навсего байтом в огромной таблице. И который в любой момент может стать False...
                  Ответить
      • Ну дык - знал бы эбаут, срал бы в stdout... Точнее, сразу велосипед бы соорудил. Мне не столько памяти жалко, сколько от подляны такой обидно: завалиться ко мне в стек без проса и орать, что я что-то испортил.

        А сисколлы ты тут сам реализуешь. Рантайм же не знает, в какой порт ты срешь (а, может, вообще по SPI передаешь), так что пишешь какой-нибудь MySerialOutputChar(char c) { while (!TRANSMIT_BUF_EMPTY()); TRANSMIT(c); } , ну а если printf хочешь использовать, то подсовываешь ему _write(<...>) { while (len--) MySerialOutputChar(*data++); } и все типа работает.
        Ну, можно, конечно, везде MySerialOutputString понавтыкать, но хотелось же %d%08X.
        Ответить
    • Опытная сишкоблядь с легкостью решает не существующие в паскалье проблемы.
      Ответить
    • А вообще какие ЯП и какие библиотеки сейчас можно использовать с 8К RAM?
      Ответить
    • показать все, что скрытоБамп отсосу сишкоблядей!
      Ответить
    • Заблудился сталкер в лесу; идёт и кричит: "Эй, ау, кто-нибудь! Помогите!"
      Вдруг навстречу ему - здоровенная такая, страхолюдина, и говорит жалостливо:
      "Чего орешь, ужин ты мой?.."
      Ответить

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