Длина каждого строкового аргумента - PullRequest
1 голос
/ 03 апреля 2020

Недавно я начал немного разбираться в функциях stdarg.h, потому что хочу иметь что-то похожее на printf, но вместо записи в консоль я хочу вернуть его в виде строки.

Вот то, что я до сих пор придумал:

char *write(const char *format, ...)
{
    // init
    va_list arg;
    char *string;

    va_start (arg, format);
    vsprintf (string, format, arg);

    // done
    va_end (arg);
    return string;
}

Теперь проблема в том, что string не зарезервировала память, и именно здесь мне нужна помощь, чтобы исправить эту функцию, как Я пока не нашел решения.

Заранее спасибо

1 Ответ

5 голосов
/ 03 апреля 2020

Используйте snprintf(NULL, 0, чтобы проверить, как долго вам нужен буфер. Затем выделите память. Затем напечатайте в строку.

char *my_write(const char *format, ...) {
    va_list va;
    va_start(va, format);

    // remember to have a separate va_list for each v*print function
    va_list va2;
    va_copy(va2, va);
    const int len = vsnprintf(NULL, 0, format, va2);
    va_end(va2);

    char *string = malloc((len + 1) * sizeof(*string));
    if (string != NULL) {
       vsprintf(string, format, va);
    }
    va_end(va);

    return string;
}

Как предложено @IanAbbott в комментариях, вы можете дважды вызывать va_start, что, похоже, значительно упрощает код:

char *my_write(const char *format, ...) {
    va_list va;

    va_start(va, format);
    const int len = vsnprintf(NULL, 0, format, va);
    va_end(va);

    char *string = malloc((len + 1) * sizeof(*string));
    if (string == NULL) {
       return NULL;
    }

    va_start(va, format);
    vsprintf(string, format, va);
    va_end(va);

    return string;
}

На платформах с с glib c вы также можете использовать vasprintf. Обратите внимание, что имя write уже используется функцией posix write () , я предлагаю использовать другое имя. С расширением vasprintf GNU оно становится просто:

#define _GNU_SOURCE
#include <stdio.h>
char *write2(const char *format, ...) {
    va_list va;
    va_start(va, format);
    char *string;
    const int err = vasprintf(&string, format, va);
    va_end(va);
    if (err == -1) {
          return NULL;
    }
    return string;
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...