LINUX.ORG.RU

«легкий» printf() и «удобное выравнивание»

 , ,


0

1

добрый день

данный выкрутас

printf("arg: %02i:%02i:%02i, ",arg[0], arg[1], arg[2]);

прокатывает только при подключении «полного» фарша!

#
# Floating point printf version & Math-lib
#
-Wl,-u,vfprintf -lprintf_flt -lm

как выкручиваемсЯ? если не желательно использовать «толстый» вариант?

tag: avr avr-gcc print

★★★★

Ответ на: комментарий от BackDoorLover

ну да...
я по описанию не вижу, что это что-то, более чем обычная реализация printf, а наборот, облегченная версия, поэтому и сомнения :о)

с реализацией «принта» вопросов-то и нет! :о)

sunjob ★★★★
() автор топика
Последнее исправление: sunjob (всего исправлений: 5)
Ответ на: комментарий от goto-vlad

no

Formatting

Like printf, nanoprintf expects a conversion specification string of the following form:
[flags][field width][.precision][length modifier][conversion specifier]

Flags

None or more of the following:
    0: Pad the field with leading zero characters.
    -: Left-justify the conversion result in the field.
    +: Signed conversions always begin with + or - characters.
    : (space) A space character is inserted if the first converted character is not a sign.
    #: Writes extra characters (0x for hex, . for empty floats, '0' for empty octals, etc).

или я ошибаюсь?

sunjob ★★★★
() автор топика
Последнее исправление: sunjob (всего исправлений: 1)
Ответ на: комментарий от sunjob

Задание ширины поля, забивание нулями работают, но «чистого» printf там нет, как видно из описания, только snprintf или «pprintf» (с указателем на функцию для вывода каждого символа).

goto-vlad
()
Ответ на: комментарий от goto-vlad

я жешь и говорю, надо будет добраться до железки, потестировать :о)

sunjob ★★★★
() автор топика
Последнее исправление: sunjob (всего исправлений: 1)
Ответ на: комментарий от goto-vlad

да ты человек!

спасибо, действительно отрабатывает! жму мужественную руку!!! :о)

жаль, что нельзя напрямую использовать print() ну и да ладно, все равно для отладки :о)

sunjob ★★★★
() автор топика
Последнее исправление: sunjob (всего исправлений: 1)
Ответ на: да ты человек! от sunjob

Так это не мне спасибо, а автору этой библиотеки.

жаль, что нельзя напрямую использовать print() ну и да ладно, все равно для отладки :о)

А если попробовать использовать npf_pprintf с указателем на функцию, которая будет сливать данные куда надо?

goto-vlad
()
Ответ на: комментарий от goto-vlad

да я что-то набегом не понял как его вообще употреблять... там примеры для малевичей... :о)

p.s. да, и этот фокус проходит! :о)

sunjob ★★★★
() автор топика
Последнее исправление: sunjob (всего исправлений: 1)
Ответ на: комментарий от sunjob

да я что-то набегом не понял как его вообще употреблять… там примеры для малевичей… :о)

#include <stdarg.h>
#include <unistd.h> // write

#define NANOPRINTF_IMPLEMENTATION
#include "nanoprintf.h"

static void
func(int ch, void *data) // наш коллбек
{
	static char buf[1024]; // деревня
	static char *pBuf = buf;

	(void)data;

	const size_t size = pBuf - buf;

	if (size == sizeof(buf) || ch == 0) // заполнили буфер или получили конец строки
	{
		write(STDOUT_FILENO, buf, size); // для примера
		pBuf = buf;
	}
	*pBuf++ = (char)ch;
}

static __attribute__((__format__(__printf__, 1, 2))) int
myPrintf(const char *fmt, ...) {
    va_list args;
    va_start(args, fmt);
    const int n = npf_vpprintf(func, NULL, fmt, args);
    va_end(args);
    return n;
}

int main(void)
{
	int arg[] = { 23, 59, 59 };

	myPrintf("arg: %02i:%02i:%02i, ", arg[0], arg[1], arg[2]);

	return 0;
}

Пример деревенский, но для объяснения сойдет.

goto-vlad
()
Ответ на: комментарий от sunjob

p.s. да, и этот фокус проходит! :о)

Ну и хорошо. У меня эта библиотека давно в избранном валялась, теперь пригодилась :)

goto-vlad
()
Ответ на: комментарий от goto-vlad

да я уже проверил, у меня осталось некоторое непонимание

параметр pc_ctx в конечном итоге он не используется :о)

int npf_vpprintf(npf_putc pc, void *pc_ctx, char const *format, va_list vlist) { ...

я сначало не понял, почесал тыкаваку, может зря чесал?! :о) проверил, вроде работает

////////////////////////////////////////////////////////////////////////////////
void _putc(int i, void* ptr)
////////////////////////////////////////////////////////////////////////////////
{
if ( ((const char*) ptr+i) == 0 ) { return ; }
putchar( (int)((const char*)ptr+i) );
}
////////////////////////////////////////////////////////////////////////////////
int main(void)
////////////////////////////////////////////////////////////////////////////////
{
usart_init();
printf("### RTC3231 ###\n");

char buf[16];
printf("npf_snprintf()\n");
npf_snprintf(buf, sizeof(buf), "%02i %02i %02i", 1, 2, 30);
printf("%s\n", buf);

printf("npf_pprintf()\n");
npf_pprintf(_putc, NULL, "%02i %02i %02i", 1, 2, 30);

while(1)
  {
  _delay_ms(1000);
  }
}
////////////////////////////////////////////////////////////////////////////////

-->

### RTC3231 ###
npf_snprintf()
01 02 30
npf_pprintf()
01 02 30
sunjob ★★★★
() автор топика
Ответ на: комментарий от sunjob
void _putc(int i, void* ptr)
{
if ( ((const char*) ptr+i) == 0 ) { return ; }
putchar( (int)((const char*)ptr+i) );
}

Это какая-то дичь, эта функция должна принимать символ и произвольные данные пользователя, а не индекс и буффер. Просто повезло, что был передан NULL в качестве ctx, и i (на самом деле код символа, был сложен с 0) и преобразован в указатель и обратно перед передачей putchar. Но gcc с -Werror=pointer-to-int-cast такой код даже не скомпилирует.

goto-vlad
()
Ответ на: комментарий от sunjob

Я думаю, с putchar должно быть так:

void _putc(int ch, void *ptr)
{
if (ch == 0) { return ; }
putchar(ch);
}

А так, да, если функции не нужен параметр «ctx/user_data», то он будет NULL и заигнорен в большинстве случаев.

goto-vlad
()
Ответ на: комментарий от goto-vlad

а на 8-битной так вообще ведро со свистом пролетает :о)
отсюда логичный вывод ...

к стати, да! объявляется конкурс на самый смешной вывод из этой истории :о)

приз - вечная память в наших сердцах... в сердцах память... гм ... эвона я загнул ... :о)

sunjob ★★★★
() автор топика
Последнее исправление: sunjob (всего исправлений: 4)
Ответ на: комментарий от sunjob

Один из способов избежать ругательств компилятора на неиспользованную переменную, можно было использовать __attribute__((unused)).

goto-vlad
()
Ответ на: комментарий от goto-vlad

у нас тут все как-то попроще :о) спасибо

sunjob ★★★★
() автор топика
Ответ на: комментарий от goto-vlad

небольшие тесты

смотри, я тут померил вес бинарников

----------------------------------------------------
 size | version of printf/library           | %02i | 
----------------------------------------------------
13428 | minimal ver. of printf              | NO   |
14614 | normal                              | YES  |
18877 | maximal                             | YES  |
----------------------------------------------------
22918 | minimal ver. of printf & nanoprintf | YES  |   
----------------------------------------------------

получается, что, все же оптимально использовать родную версию (нормальный вариант)

точнее, в нашем случае :о)

sunjob ★★★★
() автор топика
Ответ на: небольшие тесты от sunjob

Плюс можно попробовать поотключать ненужные возможности через #define NANOPRINTF_USE_* 0. Например %n сразу может пойти под нож, он мало кому нужен.

goto-vlad
()

Если формат фиксирован, то может проще свой велосипед наваять? Вроде несложно. По размеру бинарника точно минимум будет.

monk ★★★★★
()
Ответ на: комментарий от goto-vlad

MAX & NORMAL

в двух словах - это версии слинкованной библиотеки printf

настройка в makefile:

PRINTF_LIB_MIN   = -Wl,-u,vfprintf -lprintf_min
PRINTF_LIB_FLOAT = -Wl,-u,vfprintf -lprintf_flt

sunjob ★★★★
() автор топика
Ответ на: комментарий от monk

По размеру бинарника точно минимум будет

в таблице привел размеры, с достаточно хорошим «велосипедом» размер получился в полтора раза больше
да и «формат» не фиксирован, обычно там может быть что угодно!
ну... во всяком разе, в моем случае :о)

sunjob ★★★★
() автор топика
Последнее исправление: sunjob (всего исправлений: 3)
Ответ на: По размеру бинарника точно минимум будет от sunjob

в таблице привел размеры, с достаточно хорошим «велосипедом» размер получился в полтора раза больше

Я имел в виду вместо

printf("arg: %02i:%02i:%02i, ",arg[0], arg[1], arg[2]);

если известно, что arg[i] от 0 до 99, то

unsigned char ch = 0;
char ch_buf[12];

char *ch2(int c)
{
  char* res = ch_buf + ch;
  ch_buf[ch++] = 0x30 + c % 10;
  ch_buf[ch++] = 0x30 + (c / 10 % 10);
  ch_buf[ch++] = 0;
  return res;
}

printf("arg: %s:%s:%s, ",ch2(arg[0]), ch2(arg[1]), ch2(arg[2]));
ch = 0;

да и «формат» не фиксирован, обычно там может быть что угодно!

Если весь printf нужен, тогда без вариантов.

monk ★★★★★
()
Ответ на: комментарий от sunjob

по моему, «этого» у нас нет :о)

Я имел в виду разные NANOPRINTF_USE_* из самого nanoprintf.h.

goto-vlad
()
Ответ на: MAX & NORMAL от sunjob

в двух словах - это версии слинкованной библиотеки printf

Я о разработке под avr знаю примерно ничего, поэтому вопрос может показаться странным, но разве нельзя полностью отказаться от родного printf и использовать этот? В твоей таблице я этого не увидел.

goto-vlad
()
Последнее исправление: goto-vlad (всего исправлений: 1)
Ответ на: комментарий от goto-vlad

под avr знаю примерно ничего

я тоже :о)

понятное дело, подумал и об этом, но...
там такая фигня, если задизеблить все, свЯзанное с подключением библиотек printf, то линкуется минимальная версия, возможно есть что жестко и по минимуму необходимо (звучит глуппо, но пусть знатоки поправят :о)))

ну а так принты используются в основном только при отладке

p.s. хотя надо погрысть этот камешек, посмотреть ключики :о)

cut from makefile

#
# If this is left blank, then it will use the Standard printf version.
#
#PRINTF_LIB =
#PRINTF_LIB = $(PRINTF_LIB_MIN)
#PRINTF_LIB = $(PRINTF_LIB_FLOAT)

sunjob ★★★★
() автор топика
Последнее исправление: sunjob (всего исправлений: 4)
Ответ на: комментарий от goto-vlad
#define NANOPRINTF_USE_FIELD_WIDTH_FORMAT_SPECIFIERS  1
#define NANOPRINTF_USE_PRECISION_FORMAT_SPECIFIERS    0
#define NANOPRINTF_USE_LARGE_FORMAT_SPECIFIERS        0 // error SSIZE_T / ssize_t' undeclared
#define NANOPRINTF_USE_FLOAT_FORMAT_SPECIFIERS        0 // error --//--
#define NANOPRINTF_USE_WRITEBACK_FORMAT_SPECIFIERS    0
#define NANOPRINTF_IMPLEMENTATION

-->

15997 - size

все равно чуть больше :o)

sunjob ★★★★
() автор топика

Если не нужен float, то у меня есть простая замена printf: https://github.com/punzik/uprintf

Я когда-то очень давно написал это для какого-то МК, и с тех пор оно кочует из проекта в проект. Оформил вот для публики, может будет кому-то полезно. Там, кстати, есть полезные фичи, которых нет в printf. Например указание символа для выравнивания, или указание ширины выравнивания через аргумент функции.

Puzan ★★★★★
()
Ответ на: комментарий от Puzan

может будет кому-то полезно.

Спасибо, надо будет глянуть. За %b +1.

Там, кстати, есть полезные фичи, которых нет в printf. … указание ширины выравнивания через аргумент функции.

Это вроде и в printf есть printf("%*i\n", 5, 123);. Или имелось в виду что-то другое?

goto-vlad
()
Последнее исправление: goto-vlad (всего исправлений: 1)
Ответ на: комментарий от goto-vlad

Да, это имелось в виду. Давно писал, забыл. Минус одна фича :)

Puzan ★★★★★
()
Ответ на: комментарий от Puzan

набегом-наскоком :о)

main$ make
gcc -Os -m32 -o test test.c uprintf.c
uprintf.c: In function ‘print_string’:
uprintf.c:74: error: ‘for’ loop initial declaration used outside C99 mode
uprintf.c:83: error: ‘for’ loop initial declaration used outside C99 mode
make: *** [test] Error 1

+

lib/uprintf.c:328:5: sorry, unimplemented: nested function trampolines not supported on this target

int psn(char *str, int size, const char *fmt, ...)
    ^
да, без вложения как-то не весело получается :о)
будем разбираться, где там мой топорик... колунчик...

sunjob ★★★★
() автор топика
Последнее исправление: sunjob (всего исправлений: 3)
Ответ на: набегом-наскоком :о) от sunjob

По первой ошибке надо добавить опцию gcc -std=c99.

По второй: если не нужун аналог snprintf, то можно закомментить функцию int psn(char *str, int size, const char *fmt, ...).

Обновил на гитхабе. Вообще, код простой, можно поправить для совместимости с древними версиями.

Puzan ★★★★★
()
Последнее исправление: Puzan (всего исправлений: 1)
Ответ на: комментарий от sunjob

Эту функцию нужно определить у себя в коде, в ней должен выводиться символ на твой stdout (UART или чего там у тебя). В тестовом примере она оборачивает fputc.

Puzan ★★★★★
()
Последнее исправление: Puzan (всего исправлений: 1)
Ответ на: комментарий от sunjob

put_char используется только в функции void p(const char *fmt, ...), которая просто обертка для void pv(put_char_func pc, const char *fmt, va_list ap). Посмотри в коде, там всё просто.

Puzan ★★★★★
()
Ответ на: комментарий от Puzan

ну да ... вот щас вот ... фигушки и рассматриваю... как баран на новый велосипет... не хотит пинчатать :о)

а точно не надо инициировать ничего? :о)

sunjob ★★★★
() автор топика
Последнее исправление: sunjob (всего исправлений: 2)
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.