printf和casting float参数 [英] printf and casting float arguments

查看:194
本文介绍了printf和casting float参数的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

  int ret = vprintf(format,args); 

args 我不知道是什么实际上推在堆栈上。
格式是一个字符串,我可以读。



上面的方法工作,直到我必须打印浮点数。当我打印float我得到一些奇怪的数字...



我检查,如果我调用 float fArg = *(reinterpret_cast< const float * ;(args) - 然后打印 fArg 打印正确的值(我试过args只包含一个实际参数) p>

所以我可能需要特殊的行为%... f子格式 - 应该将
转换为float。( ... 符号表示精度,宽度等可以在 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()以外的任何操作。






今年早些时候,我写了一个 printf()格式字符串(它支持 n $ 符号以指定哪个参数指定特定的值)。我创建的头包含( PFP_Errno PFP_Status FWP_None FWP_Star ):

  typedef struct PrintFormat 
{
const char * start; / *指向%符号* /
const char * end; / *指向转换说明符的指针* /
PFP_Errno错误; / *转换错误号* /
短宽度; / *字段宽度(FPW_None为无,FPW_Star为*)* /
短精度; / *字段精度(FPW_None为无,FPW_Star为*)* /
short conv_num; / * n of%n $(0表示无)* /
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() - 隔离并解析下一个printf()转换规范
**
** 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)
** {
** ...使用填充pf来标识格式...
** start = pf.end + 1;
**}
** if(rc == PFP_Error)
** ...报告错误,可能使用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指定的精度。您可能有一个更长的格式,但只有由几个字符无重复,即使你使用了数十或数百个参数。


As a part of my program I use:

int ret = vprintf (format, args);

The args I get on the stack and I can't know what actually was pushed on the stack. The format is a string, which I can read.

The above approach works until I have to print floats. When I print float I get some strange numbers ...

I checked that if I call float fArg = *(reinterpret_cast<const float*>(args) - and then print fArg the correct value is printed (I tried it when args was consisted only from one actual argument)

So probably I need special behavior for "%...f" sub-format - the corresponding (sub)argument should be cast to float. (The ... notation means that precision, width etc. could be added before f) How can I implement it?

解决方案

Note that with variable-length argument lists, all float values are promoted to (and passed as) double values. You cannot reliably use:

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

because the language never places a float value on the stack. You would have to write:

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

This may be your entire problem.


If not, it is likely that you will need to scan the format string, and isolate the format specifiers, and implement a significant portion of the core printf() code. For each specifier, you can collect the appropriate value from the args. You then simply call the appropriate printf() function on a copy of the initial segment of the format string (because you can't modify the original) with the correct value. For your special case, you do whatever it is you need to do differently.

It would be nice to be able to pass the args parameter to vprintf() so it deals with collecting the type, etc, but I don't think that's portable (which is undoubtedly a nuisance). After you've passed a va_list value such as args to a function that uses va_arg() on it, you cannot reliably do anything other than va_end() on the value after the function returns.


Earlier this year, I wrote an printf()-style format string analyzer for POSIX-enhanced format strings (which support the n$ notation to specify which argument specifies a particular value). The header I created contains (along with enumerations for PFP_Errno, PFP_Status, FWP_None and 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);

The parse function analyzes the source and sets the appropriate information in the structure. The create function takes a structure and creates the corresponding format string. Note that the conversion specifier in the example (%3$+-*2$.*1$llX) is valid (but a little dubious); it converts an unsigned long long integer passed as argument number 3 with a width specified by argument 2 and a precision specified by argument 1. You probably could have a longer format, but only by a couple of characters without repetition, even if you used tens or hundreds of arguments in total.

这篇关于printf和casting float参数的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆