I use the codeblock.
when the code is:
printf("%.1f", 1);
The program can run,and the output is 0.0. I want to know why.
`
Change it to:
printf("%.1f", 1.0);
f conversion specifier requires an argument of type double but you are passing an int value (1 is of type int). Passing an argument of the wrong type to printf invokes undefined behavior.
Using wrong format specifier invokes undefined behavior. You may get either expected or unexpected result. Use %d instead as the argument passed to printf is int type or change 1 to 1.0 if you are using %f.
C11: 7.21.6 (p9):
If a conversion specification is invalid, the behavior is undefined.282) If any argument is
not the correct type for the corresponding conversion specification, the behavior is
undefined.
The format is incorrect , you should give a float or a double as the second argument to the printf function. The gcc compiler also gives a warning on such mistakes by programmers.
printf("%.1f",1.23);
Output:
1.2
Be carefull with these kind of mistakes. Good luck!
Related
I have this code in C-
#include <stdio.h>
void main(void)
{
int a=90;
float b=4;
printf("%f",90%4);
}
It gives an output 0.0000,I am unable to understand why???
i know that 90%4 returns 2 and the format specifier specified is %f,which is for double,but what I expect is-
That it will give an error,but it is showing 0.0000 as output.
Can someone please explain why?
The type of 90%4 will be int.
The behaviour on using %f as the format specifier for an int is undefined.
The output could be 2, it could be 0. The compiler could even eat your cat.
This discrepancy comes about because the compiler and library do not communicate regarding types. What happens is that your C compiler observes that printf is a variadic function taking any number of arguments, so the extra arguments get passed per their individual types. If you're lucky, it also parses the format string and warns you that the type doesn't match:
$ gcc -Wformat -o fmterr fmterr.c
fmterr.c: In function ‘main’:
fmterr.c:6:2: warning: format ‘%f’ expects argument of type ‘double’,
but argument 2 has type ‘int’ [-Wformat=]
printf("%f",90%4);
^
But this is still just a warning; you might have replaced printf with a function with different behaviour, as far as the compiler is concerned. At run time, floating point and integer arguments may not even be placed in the same place, and certainly don't have the same format, so the particular result of 0.0 is not guaranteed. What really happens may be related to the platform ABI. You can get specified behaviour by changing the printf argument to something like (float)(90%4).
printf is a variadic function. Such functions are obscure, with no type safety worth mentioning. What such functions do is to implicitly promote small integer types to type int and float to double, but that is it. It is not able to do more subtle things like integer to float conversion.
So printf in itself can't tell what you passed on it, it relies on the programmer to specify the correct type. Integer literals such as 90 are of type int. With the %f specifier you told printf that you passed a double, but actually passed an int, so you invoke undefined behavior. Meaning that anything can happen: incorrect prints, correct prints, program crash etc.
An explicit cast (double)(90%4) will solve the problem.
%f expects a double and you pass int(90%4=2) in printf. Thus ,leading to Undefined Behaiour and can give output anything .
You need to explicitly cast -
printf("%f",(double)(90%4));
Don't try this as compiler will generate an error (as pointed by #chux Sir )-
printf("%f",90%(double)4);
In short: there is no error checking for format specifiers. If your format is looking for a double, then whatever you pass as an argument (or even if you pass nothing) will be interpreted as a double.
By default, 90%4 gives an integer.
If you print integer with %f specifier, it will print 0.
For example, printf("%f", 2); will print 0.
You typecast result with float, you will get 2.00000.
printf("%f",(float) (90%4)); will print 2.00000
Hope it clarifies.
The following code always prints "0.00". I was expecting "7888". Should I convert it to double?
long l = 7888;
printf("%.2f", l);
%.2f is not a valid format for a long. You can cast it to double:
long l = 7888;
printf("%.2f", (double)l);
Here is a table (scroll a bit down) where you can see which codes are allowed for all number types.
%f expects a double and l variable is a long. printf() does not convert it's arguments to a type required by the format specifier all-by-itself magically.
FWIW, printf() being a variadic function, default argument promotion rule is applied on the supplied arguments, and it does not change a long to double, either. If at all, you want that conversion to happen, you have to cast the argument value explicitly.
You need to write something like
printf("%.2f", (double)l);
Please note, this code invokes undefined behaviour, without an explicit cast. Reference, C11, chapter §7.21.6.1, fprintf()
[....] If any argument is
not the correct type for the corresponding conversion specification, the behavior is undefined.
The %f format specifier expects a double, but you're passing it a long, so that's undefined behavior.
If you want to print it properly, you need to either use the %ld format specifier to print it as a long:
printf("%ld", l);
Or cast l to double to print it as a floating point number:
printf("%.2f", (double)l);
I was expecting "7888".
This happens because you are trying to print LONG with FLOAT identifier.
The compiler complains about that if you turn your setting on:
program.c:5:5: error: format ‘%f’ expects argument of type ‘double’, but argument 2 has type ‘long int’ [-Werror=format=]
printf("%f", l);
^
cc1: all warnings being treated as errors
.
Should I convert it to double?
By the way you can cast it too, if this is what you really need.
I think this is what you realy need:
#include<stdio.h>
int main(void){
long l = 7888;
printf("%ld", l);
return 0;
}
7888
You cannot printf a long proberly with a float identifier. What do you want do achieve?
The C99 standard talks about doubles in the specification for fprintf (which subsequently applies to printf). It says "a double argument representing a floating-point number is converted..." Then in paragraph 9, it says:
If a conversion specification is invalid, the behavior is undefined.
If any argument is not the correct type for the corresponding
specification, the behavior is undefined.
So I would expect the following to be undefined behavior but my compiler doesn't warn about it.
double d = 2.0;
float f = 2.0f;
printf("%f", d);
printf("%f", f); // here
On the other hand, the specification for fscanf says "floating point number" instead of double. Is it undefined behavior like this user claims?
Passing a float to printf is not undefined behavior--it's simply an impossibility. The float will be promoted to double before printf receives it.
scanf is different because what you're (at least normally) passing to scanf are pointers rather than the data objects themselves. Since you're passing a pointer to the original data, with scanf you need to distinguish between a float and a double.
float in vararg functions are always promoted to double.
scanf deals with pointers.
If I try to print a float as an int, this code:
main () {
float a = 6.8f;
printf("%d", a);
}
prints 1073741824, while this code:
main () {
float a = 9.5f;
printf("%d", a);
}
prints 0.
Is the output undefined? Also when is %f used with integer and %d used with double?
Not only the output, but the entire program has undefined behavior, since type of the value you are passing to printf() does not match the type the format string expects.
From the C99 standard section 7.19.6.1 The fprintf function:
If any argument is not the correct type for the corresponding conversion specification, the behavior is undefined.
%d expects an int, not a float, so the program has undefined behaviour (including the output).
As described in previous answers if the print format doesn't match the type passed, it shows undefined behavior.
If you want to view integer as float u need to typecast it.
int j = 5;
printf("%f",(float)(j));
This will print output as 5.0 ie as a floating digit number
The C Standard says that the printf format must match the type passed in. If it doesn't, the behavior is expressly undefined:
C99, 7.19.6.1 # 9 (fprintf)
If a conversion specification is invalid, the behavior is
undefined.239) If any argument is not the correct type for the
corresponding conversion specification, the behavior is undefined.
According to section 4.9.6.1 of the C89 draft, %d is a character that specifies the type of conversion to be applied.
The word conversion implies, in my opinion, that printf("%d", 1.0) is defined.
Please confirm or refute this.
The conversion is the conversion of a language value to a lexical representation of that value.
Your theory is wrong; behavior is undefined. The spec says (7.19.6.1p8 and 9, using C99 TC2):
The int argument is converted to signed decimal in the style [−]dddd.
And
If any argument is not the correct type for the corresponding conversion specification, the behavior is undefined.
Printf is a varargs function, so no conversion is possible. The compiler just arranges to push a double onto the arguments list. Printf has no way to find out that it's a double versus an int versus an elephant. Result? Chaos.
The word "conversion" here is referring to the conversion of an int (which is the only acceptable argument type here) to a string of characters that make of the decimal representation of that int. It has nothing to do with conversion from other types (such as double) to int.
Not sure if it's officially undefined or an error - but it's wrong!