Reputation:
The following code prints 99 where 'c' was converted implicitly to 99.
printf("%d", 'c');
But the following code prints 0.000000:
printf("%f", 23);
Why in the second case was the integer 23 not converted into 23.00000 as was in the first case? Does this reflect poor implementation of implicit conversion in C? Thanks in advance.
EDIT: If there is no promotion possible from int to float as one of the answer suggests, then why is there a promotion of int to float when we write
float x = 23;
Why so?
Upvotes: 4
Views: 260
Reputation: 5421
printf
is a variadic function, which means its arguments (apart from the first one) are effectively untyped by the time they are accessed. This rules out any kind of smart type conversion inside printf
's argument list (although there are certain default conversions that take place, kind of blindly and irrespective of the format specifiers).
In the first example, 'c' is already an int
. But in the case of the float, it is not performing the conversion necessary to turn an int
into a float
because the compiler doesn't know it should, or more precisely, according to the spec, there is nothing to do but believe the format specifier is the source of truth regarding the type. It believes the data to to already be a float because the format specifier %f
is telling it so, and it cannot see the type of the 23 that is passed in.
This makes it very easy for the developer to accidentally cause a crash-- the developer has to make sure the format specifiers (e.g. %d) match up to the data supplied themselves. For example, mixing a "%s" specifier with an int
input would cause a runtime crash because the compiler will simply "believe" the format specifier is not wrong. Even worse, try omitting the data entirely... printf("%f %f %f")
will cause it to look for arguments that don't even exist, which will crash. Sadly the compiler must accept and build this crashing code.
If you care to see the conundrum more closely, google va_list
/va_start
/va_stop
, which printf
uses. Understand that this mechanism allows us to loop through the data sent into printf
, but, the type information is lost. It is untyped binary data, and to use it, it uses the format specifier %f
to realize that a float is even there. It then interprets the binary data as a float
and writes it into the string before showing it.
Another angle to look at it from is that the compiler ignores string contents like %f
in its type system... %f
is compiled but it is applied only at runtime while running the function. But at runtime, all type information is lost-- C has a type system but it is compile time only. Basically, string data like %f
and the C type system are completely foreign concepts that never communicate. So try to imagine your program without any string data like %f
. How could the compiler know to run the compile-time int->float conversion?
Again, this only applies to variadic functions, not regular function calls. Ordinary function calls exhibit type-handling that is similar to most modern languages. Variadic functions, on the other hand, are unique to C. Similar to void *
pointers, they should be considered dangerous and used with care.
EDIT:
float x = 23;
results in a promotion because the language has a functional type system (although types are ONLY known at compile time). The type system just doesn't work inside variadic function arguments, i.e. the inputs to printf
.
Upvotes: 9
Reputation: 241731
In C, 'c' is an int
. No conversion is performed.
Even if it were a char
(as it is in C++), char
is an integer type, and in the argument lists of variadic functions like printf
, all variadic arguments undergo arithmetic promotion, which will automatically widen a char
to an int
, or a float
to a double
-- but not an int
to a double
.
Upvotes: 12