In my main function, I use the following code

float f = 32.0;
func("test string %f", f);

func (these are all example names) is declared as following

void func(const char *str, ...);

In my implementation of this function, I use a union called all_types to obtain the value of the arguments that are passed

union all_types
{
    void *v;
    CLObject *obj;
    char *s;
    long l;
    char c;
    float f;
    int i;
    double d;
};

and then give a value to that union like this

union all_types *o = calloc(1, sizeof(union all_types));
while ((o->v = va_arg(list, void *)) != NULL)

Now, when I know the argument is a float, the value for it will be very strange (I set a breakpoint to figure it out). The i and l values on the union will be 32, as they should. However, the f value is some weird number like 0.00000000000000000000000000000000000000000013592595. Does anyone know why I am getting this behavior? This function works for every other type of object I have tested.

有帮助吗?

解决方案

The va_arg macro's second argument is the actual type of the actual argument. No conversion takes place as a result of the va_arg invocation. If you don't know the actual type of the actual argument, you're out of luck because there is no way to find out.

Note that default argument conversions do take place in the call itself, so it is impossible to receive a float, char or unsigned short. (The float will be converted to double and the other two to int or unsigned int, depending.)

This is why printf formats make you specify the type of the argument, except for float.

其他提示

What you are doing invokes undefined behavior, variadic functions will convert floats to double and the undefined behavior comes in because void * is not compatible with double and so you can have no expectation as to the result. We can see this by going to the draft C99 standard section 7.15.1.1 The va_arg macro which says:

[...]If there is no actual next argument, or if type is not compatible with the type of the actual next argument (as promoted according to the default argument promotions), the behavior is undefined,[...]

The correct way to do this would be:

o->d = va_arg(list, double)

and you have the format specifier so this should be possible:

"test string %f"
             ^^
许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top