printf和cast float参数
作为我的程序的一部分,我使用:
int ret = vprintf (format, args);
我进入堆栈的args
,我不知道实际上是什么被推到了堆栈上。 格式是一个字符串,我可以阅读。
上述方法有效,直到我必须打印浮点数。 当我打印浮动时,我得到一些奇怪的数字……
我检查了如果我调用float fArg = *(reinterpret_cast(args)
– 然后打印fArg
打印正确的值(当args仅由一个实际参数组成时我尝试过)
所以我可能需要"%...f"
子格式的特殊行为 – 相应的(子)参数应该转换为float。 ( ...
符号表示在f
之前可以添加精度,宽度等)我如何实现它?
请注意,对于可变长度参数列表,所有float
值都将提升为(并传递为) double
值。 你无法可靠地使用:
float f = va_arg(args, float); /* BAD! */
因为语言永远不会在堆栈上放置浮点值。 你必须写:
float f = va_arg(args, double); /* OK */
这可能是你的整个问题。
如果没有,您可能需要扫描格式字符串,并隔离格式说明符,并实现核心printf()
代码的重要部分。 对于每个说明符,您可以从args
收集适当的值。 然后,您只需使用正确的值在格式字符串的初始段的副本上调用相应的printf()
函数(因为您无法修改原始段)。 对于您的特殊情况,您可以做任何不同的事情。
能够将args
参数传递给vprintf()
以便处理收集类型等会很好,但我不认为它是可移植的(这无疑是一种麻烦)。 在将诸如args
类的va_list
值传递给在其上使用va_arg()
的函数之后,在函数返回后,您无法在值上执行除va_end()
之外的任何操作。
今年早些时候,我为POSIX增强格式字符串(支持n$
表示法指定哪个参数指定特定值)编写了一个printf()
样式格式字符串分析器。 我创建的标题包含(以及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指定的精度。你可能可以有更长的格式,但只有几个字符没有重复,即使你使用了几十个总共有数百个参数。
没有简单,便携的方法来做到这一点; 要检查va_list
,您必须知道它包含的值的类型,并且唯一的方法是通过解析格式字符串。 实际上,你必须重新实现vprintf
一部分。 (部分,因为您仍然可以将单独的格式说明符+转换值对发送到printf
,而不用担心如何拆分float
。)