Sylvainの答えに基づいて、ここに両方asprintf()
を使用した簡単な実装をvasprintf()
示します。一方が必要な場合は、通常、もう一方も必要になるためです。また、va_copy()
C99 からのマクロを考えると、実装は簡単asprintf()
ですvasprintf()
。実際、varargs 関数を作成するときは、それらをペアにして、1 つは省略記号表記を使用し、もう 1 つは省略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()の man ページには、エラーの場合、ポインターの戻り値は不確定であると記載されていることに注意してください。質問で参照されているものを含む他のマニュアルページは、エラー時に明示的に NULL に設定されていることを示しています。C 標準委員会のドキュメント ( n1337.pdf ) では、メモリ不足時のエラー動作が指定されていません。
- asprintf() を使用する場合、関数が失敗した場合にポインターが初期化されると想定しないでください。
- asprintf() を実装する場合は、エラー時にポインタが null に設定され、確定的な動作が得られるようにします。