请注意,对于可变长度参数列表,所有float 值都会提升为(并作为)double 值传递。你不能可靠地使用:
float f = va_arg(args, float); /* BAD! */
因为该语言从不将浮点值放在堆栈上。你必须写:
float f = va_arg(args, double); /* OK */
这可能是你的全部问题。
如果没有,您可能需要扫描格式字符串,隔离格式说明符,并实现核心printf() 代码的重要部分。对于每个说明符,您可以从args 收集适当的值。然后,您只需使用正确的值在格式字符串的初始段(因为您无法修改原始段)的副本上调用适当的 printf() 函数。对于您的特殊情况,您可以做任何您需要做的不同的事情。
如果能够将args 参数传递给vprintf() 会很好,这样它就可以处理收集类型等问题,但我不认为这是可移植的(这无疑是一件麻烦事)。在将va_list 值(例如args)传递给在其上使用va_arg() 的函数后,在函数返回后,除了va_end() 之外,您无法可靠地对值执行任何操作。
今年早些时候,我为 POSIX 增强格式字符串编写了一个 printf() 样式的格式字符串分析器(它支持 n$ 表示法来指定哪个参数指定一个特定的值)。我创建的标头包含(以及PFP_Errno、PFP_Status、FWP_None 和 FWP_Star 的枚举):
typedef struct PrintFormat
{
const char *start; /* Pointer to % symbol */
const char *end; /* Pointer to conversion specifier */
PFP_Errno error; /* Conversion error number */
short width; /* Field width (FPW_None for none, FPW_Star for *) */
short precision; /* Field precision (FPW_None for none, FPW_Star for *) */
short conv_num; /* n of %n$ (0 for none) */
short width_num; /* n of *n$ for width (0 for none) */
short prec_num; /* n of *n$ for precision (0 for none) */
char flags[6]; /* [+-0# ] */
char modifier[3]; /* hh|h|l|ll|j|z|t|L */
char convspec; /* [diouxXfFeEgGAascp] */
} PrintFormat;
/*
** print_format_parse() - isolate and parse next printf() conversion specification
**
** PrintFormat pf;
** PFP_Status rc;
** const char *format = "...%3$+-*2$.*1$llX...";
** const char *start = format;
** while ((rc = print_format_parse(start, &pf)) == PFP_Found)
** {
** ...use filled in pf to identify format...
** start = pf.end + 1;
** }
** if (rc == PFP_Error)
** ...report error, possibly using print_format_error(pf.error)...
*/
extern PFP_Status print_format_parse(const char *src, PrintFormat *pf);
extern const char *print_format_error(PFP_Errno err);
extern PFP_Status print_format_create(PrintFormat *pf, char *buffer, size_t buflen);
解析函数分析源并在结构中设置适当的信息。 create 函数采用结构并创建相应的格式字符串。请注意,示例中的转换说明符 (%3$+-*2$.*1$llX) 是有效的(但有点可疑);它转换作为参数编号 3 传递的 unsigned long long 整数,其宽度由参数 2 指定,精度由参数 1 指定。你可能有更长的格式,但只有几个字符而不重复,即使你使用了十个字符或总共数百个参数。