Variadic function (va_arg) doesn't work with float, while printf does? What the difference is?

不问归期 提交于 2019-12-04 15:36:53

It's not printf that promotes the float argument to double, it is compiler that does it. In other words, by the time your va_arg or printf or any other function with variable number of arguments gets the control, all the floats are already promoted to doubles; the original floats are not available for retrieval.

The difference between printf and va_arg is that printf follows the rules set up by the standard, and request the parameter of a promoted type (i.e. double) when it sees the corresponding format specifier in the format string. Hence it successfully gets a double with the promoted value of the float in it, and produces the desired output.

On the other hand, when va_arg calls val = va_arg(vl, float) it ignores the promotion rule, and gets an invalid representation in return.

printf does not take arguments of type float.

The "%f" format specifier, for example, requires an argument of type double. "%Lf" requires an argument of type long double. There is no format that requires an argument of type float (which would be promoted to double anyway, not by printf itself but simply because of the semantics of calls to variadic functions).

So assuming printf is implemented in C, and that it uses the <stdarg.h> mechanisms to read its arguments, there is no invocation of va_arg() for type float in the implementation of printf.

Any variadic function that does attempt to invoke va_arg() for type float will have undefined behavior, since there can be no float arguments to such a function. printf works because it doesn't do that.

Arguments to variable argument functions gets special promotion rules.

The one relevant here is that passing a float as a variable argument gets promoted to a double. Meaning you cannot extract the argument as a float, as it has been passed as a double. This is done by the compiler, it has nothing to do with printf.

This means the code val = va_arg(vl, float) is not valid, as the argument is not a float, it's a double. If you really need to deal with the passed in values as a float, at best you can do

float val = (float) va_arg(vl, double)

Note that the %f specifier for printf expects an argument of type double , not a float

But what is difference? If both of them promotes float into double, why printf writes values correctly, while va_arg gives us such a nasal demons?

There's no difference, except the fact (stated in the question itself), that printf is coded in a way to treat float as double. In other words, somewhere inside printf, when the format string contains information that there should be a floating point number, the function does va_arg(vl, double), just like you did.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!