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.
答案 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.