LINUX.ORG.RU

C/C++ vprintf

 


0

1

Доброго времени суток!

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

const char* format="%i \% %s %c %x";
vprintf(format,a,b,c,d);

Каким образом можно программно определить из format, сколько параметров было передано? Что-нить стандартное есть или придется руками каждый раз считать в строчке количество '%'?

★★

vprintf() принимает всего два аргумента. Если ты имел ввиду свой велосипед с другим именем, то наверное нет, считать придется вручную. Кода кстати меньше, чем букв в твоем посте.

size_t n = 0;
for (const char *p = format; *p; p++) {
    if (*p == '\\') p++;
    else if (*p == '%' && *(++p) != '%') n++;
}
anonymous
()
Ответ на: комментарий от anonymous

Пишу один велосипед.

Если вкратце, то нужно сделать так, чтобы функция с переменным числом параметров, писала в файл эти параметры в нужном формате (vfprintf), но еще надо следить, чтобы размер файла ни на байт не превосходил определенного значения. Следовательно, надо узнать длину строкового представления всех передаваемых параметров, следовательно, для начала их бы пересчитать.

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

А если ты про количество аргументов в общем виде, то ответ нет.

anonymous
()
Ответ на: комментарий от aido

Заюзай холостой подсчет:


void
myfunc(const char *format, va_list ap)
{
    va_list ap2; va_copy(ap2, ap);
    char dummy;
    int len = vsnprintf(&dummy, 0, format, ap2);
    va_end(ap2);

    // 'ap' все еще доступен
    ...
}
anonymous
()
Ответ на: комментарий от anonymous

Кода кстати меньше, чем букв в твоем посте.

Это тебе только так кажется, код неправильный. Синтаксис строки формата несколько сложнее.

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

Следовательно, надо узнать длину строкового представления всех передаваемых параметров, следовательно, для начала их бы пересчитать.

Не обязательно писать сразу в файл. Навряд ли будешь ~printf()'ом херачить десятки KiB и более, потому сначала можно форматировать вывод в промежуточный небольшой буфер и уже его отправлять на запись в текущий файл или следующий в зависимости от длины результата.

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

Такие заявления надо сопровождать контр-кейсами, чтобы если не меня макнуть, то хотя бы ОП понимал, в чем проблема.

anonymous
()
Ответ на: комментарий от vzzo
#include <stdio.h>

int
main(int argc, char *argv[])
{
    const char *format = "\\";

    size_t n = 0;
    for (const char *p = format; *p; p++) {
        if (*p == '\\') p++;
        else if (*p == '%' && *(++p) != '%') n++;
    }

    printf("%zu\n", n);
    return 0;
}
$ ./a.out
1

Следующий.

anonymous
()
Ответ на: комментарий от BRE

The snprintf() function shall be equivalent to sprintf(), with the addition of the n argument which states the size of the buffer referred to by s. If n is zero, nothing shall be written and s may be a null pointer. Otherwise, output bytes beyond the n-1st shall be discarded instead of being written to the array, and a null byte is written at the end of the bytes actually written into the array.

Действительно.

(Если кто не в курсе, то по стандарту, если явно не указано иное, в общем виде нужно передавать валидный указатель даже при нулевой длине, например memmove(dst, src, 0)).

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

Такие заявления надо сопровождать контр-кейсами, чтобы если не меня макнуть, то хотя бы ОП понимал, в чем проблема.

Посмотрел бы man 3 printf, там ещё кроме самих данных можно задавать дополнительные атрибуты, типа

printf("%*d", width, num);
Может ещё какие-нибудь особенности найдутся если ман внимательно прочитать. Ах да, ещё есть неправльные строки типа '%.%u' которые тоже нужно понимать корректно. В общем, пока всю конструкцию правильно не разберёшь не узнаешь сколько аргументов должно быть.

mashina ★★★★★
()
Последнее исправление: mashina (всего исправлений: 1)
Ответ на: комментарий от anonymous
for (const char *p = format; *p; *p && p++)
    if (*p == '%' && *(++p) != '%') n++;

Либо невалидные форматы оставляем как UB.

for (const char *p = format; *p; p++)
    if (*p == '%' && *(++p) != '%') n++;
Вот теперь следующий :)

anonymous
()
Ответ на: комментарий от mashina

Только что смотрел. А зачем, если единственная неформатная последовательность это %%, а форматный %<whatever> в принципе не содержит процентов? Единственное, что точно сломается, это позиционные аргументы, это да.

anonymous
()
Ответ на: комментарий от mashina

Неправильные строки можно объявить UB и не переживать. Наверняка printf-like так и делают, но мне влом снова ходить на opengroup.

anonymous
()
Ответ на: комментарий от mashina

Ну, еще моя система спокойно жрет printf(«%% %.*% %d», 10, 20), выводя при этом «% % 20», как и положено.

Хорошо, убедил.

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

Неправильные строки можно объявить UB и не переживать. Наверняка printf-like так и делают,

Нет, нельзя. Невалидные строки, похоже, просто не считаются паттернами. Вообще в эти дебри ни в коем случае залезать нельзя т.к. у каждой реализации ~printf() могут быть какие-то свои особенности.

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

Возможно это уже UB, но да, слишком много всего возникает и помимо.

anonymous
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.