zlib слишком тяжёлая штука. Уж не для МК точно. Даже если и LZO. Под бинарным я подразумевал, что вместо строк распечатываются их адреса в ROM и аргументы printf'а например (естесственно нужен свой специальный printf и обратная функция). Если на C++, то можно проще (proof of concept, функции вывода естесственно переписать на такие, которые в поток отписывают тип и значение):
#include <iostream>
using namespace std;
class logger {
public:
typedef enum levels {
Fatal,
Error,
Warning,
Info,
Debug
} level;
logger(level l, const char *fmt) {
cout << "logging at level " << (int)l
<< " with format \"" << fmt << "\" ";
}
~logger() {
cout << endl;
}
logger &operator,(int arg) {
cout << " int " << arg;
return *this;
}
logger &operator,(const char *arg) {
cout << " string " << arg;
return *this;
}
logger &operator,(long arg) {
cout << " long " << arg;
return *this;
}
};
#define LOG(level, fmt, ...) logger(level, fmt), ##__VA_ARGS__
int main()
{
LOG(logger::Info, "test");
LOG(logger::Warning, "%s %u", "test", 42);
return 0;
}
Профит в том, что не нужно парсить строку формата в момент вывода. В момент декодирования лога -- нужно всё равно, но сильно проще, чем на голом C.
Вдогонку. C++ позволяет определить не только тип аргумента (путём перегрузки 100500 функций), но и факт, что аргумент является литералом (т.е. я пишу LOG(..., "blablabla"...), а не LOG(..., variable, ...)) -- литералы же лежат гарантированно в программной памяти, например. И таким образом имеем ещё один профит. Если формат или строка -- литерал (
http://stackoverfl …-only-a-string-literal), то отписываем в поток её адрес, если переменная -- уж придётся писать как есть. Вот и компрессия. Для голого C можно знать адреса начала и конца секции rodata и тоже делать выводы.