作为我的计划的一部分,我使用:
int ret = vprintf (format, args);
args
我进入堆栈,我无法知道实际上是什么被推入堆栈。
格式是一个字符串,我可以阅读。
上述方法有效,直到我必须打印浮点数。当我打印浮动时,我得到一些奇怪的数字......
我检查过,如果我拨打float fArg = *(reinterpret_cast<const float*>(args)
- 然后打印fArg
,则会打印正确的值(当args仅由一个实际参数组成时我试过了)
所以我可能需要"%...f"
子格式的特殊行为 - 应该转换相应的(子)参数
漂浮。 (...
表示法意味着可以在f
之前添加精度,宽度等
我该如何实施呢?
答案 0 :(得分:4)
请注意,对于可变长度参数列表,所有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指定的精度。您可能可以使用更长的格式,但只能使用几个字符而不重复,即使您总共使用了数十或数百个参数。
答案 1 :(得分:1)
没有简单易用的方法可以做到这一点;要检查va_list
,您必须知道它包含哪些类型的值,唯一的方法是通过解析格式字符串。实际上,您必须重新实现vprintf
的一部分。 (部分原因,因为您仍然可以将单个格式说明符+转换值对发送到printf
,而不用担心如何选择float
。)