Опираясь на Sylvain ответ, вот простая реализация как с asprintf()
, так и с vasprintf()
, потому что там, где вам нужен один, вам обычно нужен и другой. И, учитывая макрос va_copy()
из C99, легко реализовать asprintf()
в терминах vasprintf()
. Действительно, при написании функций с переменным числом аргументов очень часто полезно иметь их парами, одну с многоточием, а другую с аргументом va_list
вместо многоточия, и вы тривиально реализуете первое в терминах второго.
Это приводит к коду:
int vasprintf(char **ret, const char *format, va_list args)
{
va_list copy;
va_copy(copy, args);
/* Make sure it is determinate, despite manuals indicating otherwise */
*ret = NULL;
int count = vsnprintf(NULL, 0, format, args);
if (count >= 0)
{
char *buffer = malloc(count + 1);
if (buffer == NULL)
count = -1;
else if ((count = vsnprintf(buffer, count + 1, format, copy)) < 0)
free(buffer);
else
*ret = buffer;
}
va_end(copy); // Each va_start() or va_copy() needs a va_end()
return count;
}
int asprintf(char **ret, const char *format, ...)
{
va_list args;
va_start(args, format);
int count = vasprintf(ret, format, args);
va_end(args);
return(count);
}
Сложная часть использования этих функций в системе, где они не предусмотрены, заключается в том, чтобы решить, где должны быть объявлены функции. В идеале они должны быть в <stdio.h>
, но тогда вам не нужно будет их записывать. Итак, у вас должен быть какой-то другой заголовок, который включает <stdio.h>
, но объявляет эти функции, если они не объявлены в <stdio.h>
. И, в идеале, код должен определять это полуавтоматически. Возможно, заголовок "missing.h"
и содержит (частично):
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif /* HAVE_CONFIG_H */
#include <stdio.h>
#include <stdarg.h>
#ifndef HAVE_ASPRINTF
extern int asprintf(char **ret, const char *format, ...);
extern int vasprintf(char **ret, const char *format, va_list args);
#endif /* HAVE_ASPRINTF */
Также обратите внимание, что на этой справочной странице для asprintf() говорится, что возвращаемое значение в указатель не определен в случае ошибки. Другие справочные страницы, включая ту, на которую есть ссылка в вопросе, указывают, что она явно устанавливается в NULL при ошибке. Документ комитета по стандарту C (n1337.pdf) не определяет поведение ошибки при нехватке памяти.
- При использовании asprintf() не думайте, что указатель инициализируется в случае сбоя функции.
- При реализации asprintf() убедитесь, что указатель установлен в значение null при ошибке, чтобы обеспечить детерминированное поведение.
person
Jonathan Leffler
schedule
04.02.2011
asprintf()
говорит, что возвращаемое значение в*resultp
неопределенно в случае ошибки. Другие справочные страницы, такие как та, на которую ссылается вопрос, указывают, что при ошибке явно установлено значение NULL. При использованииasprintf()
не думайте, что указатель инициализируется в случае сбоя функции. При реализацииasprintf()
убедитесь, что указатель установлен в нуль при ошибке, чтобы обеспечить детерминированное поведение. - person Jonathan Leffler   schedule 04.02.2011