Union float and int

时间:2015-10-30 22:16:42

标签: c++ visual-studio-2012 unions

I'm little bit confused. During development of one function that based on predefined parameters, pass to sprintf function exact parameters needed based on their type, I found really strange behaviour ( something like "This is %f %d example", typeFloat, typeInt ).

Please take a look at following stripped working code:

struct Param {
 enum { typeInt,    typeFloat   } paramType;
 union {
    float f;
    int i;
 };
};

int _tmain(int argc, _TCHAR* argv[])
{
 Param p;
 p.paramType = Param::typeInt;
 p.i = -10;

 char chOut[256];
 printf( "Number is %d\n", p.paramType == Param::typeInt ? p.i : p.f );
 printf( "Number is %f\n", p.paramType == Param::typeInt ? p.i : p.f );
 return 0;
}

My expected output would be for printf( "Number is %d\n", p.paramType == Param::typeInt ? p.i : p.f );

Number is -10

but it actually printed

Number is 0

I have put a breakpoint after initialization of the Param p, and although p.paramType is defined as typeInt, actual output for if was -10.0000. Checking p.f gives some undefined value as expected, and p.i shows -10 also as expected. But p.paramType == Param::typeInt ? p.i : p.f in watch window evaluates to -10.000000.

I added second printf that prints it as float and now the output is

Number is 0
Number is -10.000000

So actually why this happens? Is it possible that this is a bug in Visual Studio (I use VS2012)?

Update:

std::cout<< (p.paramType == Param::typeInt ? p.i : p.f);

gives correct value of -10.

2 个答案:

答案 0 :(得分:5)

This is because the resulting type of the expression p.paramType == Param::typeInt ? p.i : p.f is always float (only the value is different depending on paramType), but your first format string expects an integer.

The following should work as you expect:

printf("Number is %d\n", (int)(p.paramType == Param::typeInt ? p.i : p.f));

The cout version gives you the expected output because the type of the expression being inserted (float) is deduced automatically, and so it formats it as a float. It is essentially the same as your second printf.

答案 1 :(得分:1)

The problem is twofold. First, it's with printf(). Don't use printf() in C++ code. The reason is related to the second problem. printf() does not have type safety. It does not know what types you gave it.

The second reason is the way types work. Your ternary if statement always returns a float because that's the right-most type. Since an int can be implicitly converted to a float, nothing "bad" happens (unless you're to turn on various "extra" warnings). So p.i gets converted to a float but you're telling printf() to expect an int. Therefore, undefined behavior occurs. Your program doesn't crash but it doesn't give you what you expected.