+5
- 01
- 02
- 03
- 04
- 05
- 06
- 07
- 08
- 09
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 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
Можешь использовать dprintf, ему никакой "FILE *" с "stdout" не нужен, только "int" с "STDOUT_FILENO"
int dprintf(int fd, const char *format, ...)
EDIT: Ну да: undefined reference to `some_bastard_called_sbrk'
sbrk вроде и правда не нужен, нужно ммапить в кучу
А вместо машинерии printf можно срать сисколом прямо в stdout (итебе еще повезло что там С++ с cout нет)
зы: циферки вон уже принес расщирение позиксовое, которое реализует сёмантику printf, но без CRT а поверх прямо голово write
На контроллере без MMU?
без мму бркают наверное. Ну типа вот у нас есть память, вот отсюда до сюда стек, потом брк, потом хип. Брк туда сюда двигают, и текут
так?
а так можно динамически в рантайме выбирать, что под стек что под кучу
Какая надёжность )))
З.Ы. Это тебе не интел, там у стека ограничителей обычно нету. Разве что через MPU навертеть, но он не везде есть.
А сисколлы ты тут сам реализуешь. Рантайм же не знает, в какой порт ты срешь (а, может, вообще по SPI передаешь), так что пишешь какой-нибудь MySerialOutputChar(char c) { while (!TRANSMIT_BUF_EMPTY()); TRANSMIT(c); } , ну а если printf хочешь использовать, то подсовываешь ему _write(<...>) { while (len--) MySerialOutputChar(*data++); } и все типа работает.
Ну, можно, конечно, везде MySerialOutputString понавтыкать, но хотелось же %d%08X.
Пишеш закащику: «насяника у мене тут не влезает, нужно конь троллер по лучше»
Espruino.
Вдруг навстречу ему - здоровенная такая, страхолюдина, и говорит жалостливо:
"Чего орешь, ужин ты мой?.."