scanf() and printf() are declared with:
int scanf(const char *, ...);
int printf(const char *, ...);
The ... part of those prototypes above don't help C to know what the parameter types should be. So the "usual arithmetic conversions" take place, I think. See Section 6.5.2.2 of the 1999 C standard.
For example, if you supply a float parameter then C promotes it to a double. It does that no matter what you do. Assume you did this:
double x= 45.2;
printf("%f\n", (float) x);
The C compiler sees that x is double. But that you are casting it explicitly to a float. So the C compiler causes a function call (or writes out direct code if it knows how) to convert x from a double to a float with the associated truncation of precision and possible errors that can be generated. It then sees that the result is a float. But since printf()'s prototype doesn't supply a type for that parameter, C invokes the "usual arithmetic conversions" and converts the float BACK into a double, again. That double is what gets passed to printf().
This is why %f and %lf both operate on a double even though they look like they might do different things. That's true with printf... but not so with scanf because scanf takes pointers, not actual values. So scanf will actually do different things with %f and %lf (not guaranteed to be different as it depends on the architecture and compiler design choices.)
scanf() uses pointers, but it looks to the format specifier string to tell it what those pointers mean. Explicit casting of them doesn't change any of that. So:
int num[3];
scanf("%d",(float *)&num[0]);
scanf("%d",(double *)&num[1]);
scanf("%d",(void *)&num[2]);
Should all work the same on machines where all the pointers are of the same kind and size (usually the case on most machines, but not always.) That is because the C compiler is just supplying a pointer as the 2nd parameter. Converting those pointers into different types usually doesn't change the pointer's value. The [] binds more tightly that the cast. So the C compiler treats num[
] as a unit, uses the & to generate an address to it, then casts it. But since the cast doesn't change the value, it just passes the same value regardless of the cast to the scanf() function. The scanf() function has no idea what machinations the C compiler went to, and doesn't really care. It looks at the format specifier to decide what the pointer means. So as long as the pointer ACTUALLY points to an int, regardless of what it was cast into beforehand, scanf() will do just fine.
For example,
#include
int main( void ) {
int x[3];
scanf( "%d %d %d", (int *) &x[0], (float *) &x[1], (double *) &x[2] );
printf( "%d %d %d\n", x[0], x[1], x[2] );
return 0;
}
works just fine. The main thing is that you don't mess up on the printf() part of it. Those specifiers MUST match what the usual arithmetic conversions produce.
None of that helps you, though, if you supply as a user the value 25.123 when scanf() is looking for a %d. scanf() doesn't swallow up whole decimal values when scanning for %d. It looks for integers. So the period (.) will stop it from scanning further if you used %d. If you want to accept floating point numbers with scanf() but only need integers, then you need to supply a %f or %lf AND a proper float or double receiver variable and THEN do a run time conversion to get your integer value. You CANNOT do all of that in one go with scanf() alone. For example, try the following:
#include
int main( void ) {
int i, x[3];
double y[3];
scanf( "%lf %lf %lf", &y[0], &y[1], &y[2] );
for ( i= 0; i < 3; ++i ) x[i]= (int) (y[i] + 0.5);
printf( "%f %f %f\n", y[0], y[1], y[2] );
printf( "%d %d %d\n", x[0], x[1], x[2] );
return 0;
}
As far as:
#include
float y= 25;
goes, there is no problem. The C compiler (before generating code) will actually convert 25 to 25.0 (as a double value, to start) and then observe that y is a float and do an internal (at compile time) conversion of the double value into a float value constant that is stored into the executable as a float constant. At run time, no conversions take place at all. It was all handled at compile time because 25 is a constant. Had it been a double variable or an int variable with a value that could not be known at compile time then there would need to be a run time conversion taking place and the C compiler would insert that code.