printf和cast float参数

时间:2011-11-13 21:21:51

标签: c casting printf

作为我的计划的一部分,我使用:

int ret = vprintf (format, args);

args我进入堆栈,我无法知道实际上是什么被推入堆栈。 格式是一个字符串,我可以阅读。

上述方法有效,直到我必须打印浮点数。当我打印浮动时,我得到一些奇怪的数字......

我检查过,如果我拨打float fArg = *(reinterpret_cast<const float*>(args) - 然后打印fArg,则会打印正确的值(当args仅由一个实际参数组成时我试过了)

所以我可能需要"%...f"子格式的特殊行为 - 应该转换相应的(子)参数 漂浮。 (...表示法意味着可以在f之前添加精度,宽度等 我该如何实施呢?

2 个答案:

答案 0 :(得分:4)

请注意,对于可变长度参数列表,所有float值都会提升为(并传递为)double个值。你无法可靠地使用:

float f = va_arg(args, float);  /* BAD! */

因为语言从不在堆栈上放置浮点值。你必须写:

float f = va_arg(args, double);  /* OK */

这可能是你的整个问题。


如果没有,您可能需要扫描格式字符串,并隔离格式说明符,并实现核心printf()代码的重要部分。对于每个说明符,您可以从args收集适当的值。然后,您只需使用正确的值在格式字符串的初始段的副本上调用相应的printf()函数(因为您无法修改原始段)。对于您的特殊情况,您可以做任何不同的事情。

能够将args参数传递给vprintf()会很好,所以它会处理收集类型等,但我不认为这是可移植的(这无疑是一种麻烦) 。在将va_listargs传递给使用va_arg()的函数后,除了函数后的值va_end()之外,您无法可靠地执行任何操作回报。


今年早些时候,我为POSIX增强格式字符串(支持printf()表示法指定哪个参数指定特定值)编写了n$样式格式字符串分析器。我创建的标题包含(以及PFP_ErrnoPFP_StatusFWP_NoneFWP_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。)