c - printf 和转换 float 参数

标签 c casting printf

作为我程序的一部分,我使用:

int ret = vprintf (format, args);

args我进入堆栈,但我不知道堆栈上实际压入的是什么。 格式是字符串,我可以读取。

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

我检查过如果我调用 float fArg = *(reinterpret_cast<const float*>(args) - 然后打印 fArg打印出正确的值(我在 args 仅由一个实际参数组成时尝试过)

所以我可能需要对 "%...f" 进行特殊处理子格式 - 应转换相应的(子)参数 浮。 (... 符号表示可以在 f 之前添加精度、宽度等) 我该如何实现?

最佳答案

请注意,对于可变长度参数列表,所有 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$ 符号来指定哪个参数指定一个特定的值)。我创建的 header 包含(以及 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);

parse 函数分析源代码并在结构中设置适当的信息。 create 函数接受一个结构并创建相应的格式字符串。请注意示例中的转换说明符 (%3$+-*2$.*1$llX) 是有效的(但有点可疑);它转换作为参数 3 传递的 unsigned long long 整数,宽度由参数 2 指定,精度由参数 1 指定。您可能有更长的格式,但只有几个字符没有重复,即使您总共使用了数十或数百个参数。

关于c - printf 和转换 float 参数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/8114834/

相关文章:

c - Xcode 导航栏按钮崩溃

c - 如何获取结构中的元素总数

java - 如何获取 View 的父 fragment : 的实例

c# - 从 C# 中的未知类型转换

c - printf() 打印整个数组

c - 如何将两个32位整数组合成一个64位整数?

c# - 从 linux C 到 Windows C# 的套接字问题

c - 存在内存泄漏的链表

c - C中三元运算符采用不同操作数类型的原理

c - 打印 float 的面试题