Skip to content

1.1.0 - печатает дробные числа своим кодом вместо dtostrf

Pre-release
Pre-release

Choose a tag to compare

@240974a 240974a released this 02 Sep 19:35
· 12 commits to main since this release

1.1.0 — 2 сентября 2026

Предварительный выпуск: библиотека выложена для оценки сообществом, замечания
приветствуются.

Устанавливается из репозитория — в каталоге Arduino и реестре PlatformIO её
пока нет; как это сделать, сказано в README.

Главное в этом выпуске

Дробные печатаются собственным кодом, целочисленной арифметикой, без
dtostrf. Замеры:

было стало
скорость (300 000 вызовов) 127.8 мс 12.3 мс в 10 раз быстрее
флеш, AVR 3432 2052 −1380 байт
флеш, ESP8266 266747 266535 −212 байт
флеш, ESP32 267961 268241 +280 байт

Против snprintf дробные теперь быстрее в 6.2 раза — раньше отставали в 1.25.

На ESP32 прошивка немного выросла: ветка для чисел от 2³², где дробной части у
double уже нет, печатает целую часть через uint64, а 64-битное деление там
отдельная подпрограмма.

Округление совпадает с printf и dtostrf до последнего знака, включая
правило «ровная половина — к чётному»: сверено на 316 004 значениях.

Исправлено: у -0.0 терялся знак — сравнение с нулём для отрицательного
нуля ложно.

Возможности библиотеки

Полный перечень, включая то, что было в 1.0.0.

Форматирование по образцу. Одно место вставки {} для любого типа вместо
%d, %lu и %.3f. Тип выводит компилятор, поэтому несовпадение типа или
забытый аргумент перестают быть порчей стека.

Готовые правила вывода — числа, строки в RAM и во флеше, String,
длительности, дата и время, IP-адрес, дампы памяти. Свой тип подключается одной
специализацией formatter<T>.

Необязательное значение opt(условие, префикс, значение) — условие пишется
один раз вместо двух тернарных выражений с пустыми литералами.

Журнал с уровнями, источниками и сменными приёмниками вывода. Библиотека
никуда не пишет сама: порт, сеть, карта памяти — решает приложение.

Уровни задаются раздельно по источникам, так что разговорчивую часть
приложения можно приглушить, не трогая остальные. Проверка идёт до сборки
сообщения, поэтому отброшенный вызов почти ничего не стоит.

Порог FMTLOG_COMPILE_LEVEL убирает вызовы из прошивки целиком — вместе с
образцами и значениями.

Необязательные модули. Цветной вывод (FmtColor.h) и чтение строк из
EEPROM (FmtEeprom.h) подключаются отдельно и не занимают места, пока не нужны.


Сколько это стоит

Все числа получены сборкой, не оценкой. Сравнение с snprintf на сообщениях
вида "msg a={} b={}" с двумя целыми.

Флеш

постоянная надбавка каждый вызов
AVR (Uno) 676 Б против 1574 Б у snprintf 108 Б против 97 Б
ESP8266 512 Б против 336 Б 77 Б против 59 Б

На AVR библиотека экономит флеш примерно до 86 вызовов — дальше немного
дороже. На ESP8266 экономии по флешу нет: printf там слинкован ядром
независимо от кода приложения, и FmtLog добавляется поверх. Разница — около
0.1 % флеша на полсотни вызовов.

Дробные выводятся собственным кодом, без dtostrf: на AVR это экономит
1380 байт флеша.

Цветной вывод стоит 456 байт и только когда подключён.

Оперативная память

Динамическая память не используется вовсе. Статически — буфер сообщения
(128 байт, на AVR 64) и состояние буфера: 16 байт на ESP, 7 на AVR. Размер
буфера задаётся при сборке через FMTLOG_MESSAGE_SIZE.

Скорость

против snprintf
целые в 2.2 раза быстрее
дробные в 6.2 раза быстрее

Библиотека печатает и те, и другие сама, целочисленной арифметикой, без
разбора образца во время выполнения.

Округление совпадает с printf и dtostrf до последнего знака, включая
правило «ровная половина — к чётному»: сверено на 316 004 значениях.


Платформы

платформа состояние
ESP8266 проверено сборкой
ESP32 проверено сборкой
AVR (Uno, Nano, Mega) проверено сборкой

На AVR нет IPAddress — соответствующее правило вывода там не собирается.
<type_traits> ядро AVR не поставляет, нужные признаки типов библиотека
определяет сама.

Что проверено

  • 60 тестов на машине разработчика, плата не нужна: pio test -e native
  • 14 сочетаний примеров и плат собираются; предупреждений от библиотеки нет
  • замеры размера и скорости — сборкой, а не оценкой
  • вывод дробных сверен с printf на 316 004 значениях

Известные ограничения

  • Спецификаторов ширины и точности у {} нет: число знаков после запятой
    задаётся при сборке через FMTLOG_FLOAT_DECIMALS, общий для всех значений.
  • Буфер сообщения один на приложение, поэтому журнал не переживёт вызова из
    прерывания во время сборки другого сообщения.
  • Дата и время принимают время эпохи Unix и печатаются как есть: часовой пояс
    библиотека не знает, сдвиг задаёт приложение.