I am getting output 0.23 from second printf. But typecasting gives required output. If I am not using type casting previous value is printed.
Compiler version is GCC 6.3
#include <stdio.h>
int main() {
printf("%f ", 0.23);
printf("%f", 0);
return 0;
}
LINK FOR IDE
in
> printf("%f",0);
You ask to print a double but you give an int, this is contradictory
You are not in the case where the generated code makes a double from the int because printf is not int printf(const char *, double); but int printf ( const char * format, ... ); and the compiler does not look at the format to make the necessary conversions ( but in a lot of cases the compiler warn you )
When prints access to the second argument is does to get a double using 64b and probably your int use only 32b, the behavior is undefined.
(edit, thank you #chqrlie)
I get previous float value when i am printing new value
In your case may be printf retrieves a double value from the MMX registers as opposed to the int value that was passed via the stack or regular registers... which may explain why the same value gets printed twice. But of course as always with undefined behavior, anything else could happen at any time
The problem is a combination of two factors:
The first is that for vararg functions like printf, the compiler will not do any implicit conversions of the arguments. So the 0 in the argument list is an integer constant (of type int).
The second factor is the mismatching format specifier. The printf function doesn't know anything about the arguments being passed, except what is specified in the format string. Mismatching format and argument type leads to undefined behavior. And since the "%f" specifier make printf expect a value of type double, and you have given an int value, you have such a mismatch.
Related
In this code, the multiply function's return type is char. Clearly, I'm returning a double value and printing with the double format specifier and it gives the appropriate value. If I try to print using the %c format specifier, it doesn't print anything. Either way, isn't it supposed to give an error?
#include <math.h>
#include <stdio.h>
char multiply(double x, double y)
{
return (double)(x * y);
}
int main() {
double x = 10, y = 20;
printf("%f", multiply(x, y));
}
Actually, C does not allow this.
Clearly, I'm returning a double value and printing with the double format specifier and it gives the appropriate value
No, you do not return a value of type double.
That value is converted to char before the function is left.
This is called an implicit conversion.
Using format specifier %f requires a parameter of type double. Instead you pass a char which is promoted to int for variadic functions. This parameter mismatch causes undefined behaviour. If the result looks like you wanted it, that is just by accident.
If I try to print using the %c format specifier, it doesn't print anything.
You multiple 10*20. What result do you expect if you print the value 200?
If your char is signed, then this overflows to a negative value.
That is no valid ASCII value and probably nothing that is printable.
Either way, isn't it supposed to give an error?
At least you should get some warning.
I am not sure about the implicit conversion but surely for the parameter mismatch in printf.
If you did not get one, turn up warning level.
For GCC use -Wall -Wextra.
void main()
{
clrscr();
float f = 3.3;
/* In printf() I intentionaly put %d format specifier to see
what type of output I may get */
printf("value of variable a is: %d", f);
getch();
}
In effect, %d tells printf to look in a certain place for an integer argument. But you passed a float argument, which is put in a different place. The C standard does not specify what happens when you do this. In this case, it may be there was a zero in the place printf looked for an integer argument, so it printed “0”. In other circumstances, something different may happen.
Using an invalid format specifier to printf invokes undefined behavior. This is specified in section 7.21.6.1p9 of the C standard:
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.
What this means is that you can't reliably predict what the output of the program will be. For example, the same code on my system prints -1554224520 as the value.
As to what's most likely happening, the %d format specifier is looking for an int as a parameter. Assuming that an int is passed on the stack and that an int is 4 bytes long, the printf function looks at the next 4 bytes on the stack for the value given. Many implementations don't pass floating point values on the stack but in registers instead, so it instead sees whatever garbage values happen to be there. Even if a float is passed on the stack, a float and an int have very different representations, so printing the bytes of a float as an int will most likely not give you the same value.
Let's look at a different example for a moment. Suppose I write
#include <string.h>
char buf[10];
float f = 3.3;
memset(buf, 'x', f);
The third argument to memset is supposed to be an integer (actually a value of type size_t) telling memset how many characters of buf to set to 'x'. But I passed a float value instead. What happens? Well, the compiler knows that the third argument is supposed to be an integer, so it automatically performs the appropriate conversion, and the code ends up setting the first three (three point zero) characters of buf to 'x'.
(Significantly, the way the compiler knew that the third argument of memset was supposed to be an integer was based on the prototype function declaration for memset which is part of the header <string.h>.)
Now, when you called
printf("value of variable f is: %d", f);
you might think the same thing happens. You passed a float, but %d expects an int, so an automatic conversion will happen, right?
Wrong. Let me say that again: Wrong.
The perhaps surprising fact is, printf is different. printf is special. The compiler can't necessarily know what the right types of the arguments passed to printf are supposed to be, because it depends on the details of the %-specifiers buried in the format string. So there are no automatic conversions to just the right type. It's your job to make sure that the types of the arguments you actually pass are exactly right for the format specifiers. If they don't match, the compiler does not automatically perform corresponding conversions. If they don't match, what happens is that you get crazy, wrong results.
(What does the prototype function declaration for printf look like? It literally looks like this: extern int printf(const char *, ...);. Those three dots ... indicate a variable-length argument list or "varargs", they tell the compiler it can't know how many more arguments there are, or what their types are supposed to be. So the compiler performs a few basic conversions -- such as upconverting types char and short int to int, and float to double -- and leaves it at that.)
I said "The compiler can't necessarily know what the right types of the arguments passed to printf are supposed to be", but these days, good compilers go the extra mile and try to figure it out anyway, if they can. They still won't perform automatic conversions (they're not really allowed to, by the rules of the language), but they can at least warn you. For example, I tried your code under two different compilers. Both said something along the lines of warning: format specifies type 'int' but the argument has type 'float'. If your compiler isn't giving you warnings like these, I encourage you to find out if those warnings can be enabled, or consider switching to a better compiler.
Try
printf("... %f",f);
That's how you print float numbers.
Maybe you only want to print x digits of f, eg.:
printf("... %.3f" f);
That will print your float number with 3 digits after the dot.
Please read through this list:
%c - Character
%d or %i - Signed decimal integer
%e - Scientific notation (mantissa/exponent) using e character
%E - Scientific notation (mantissa/exponent) using E character
%f - Decimal floating point
%g - Uses the shorter of %e or %f
%G - Uses the shorter of %E or %f
%o - Signed octal
%s - String of characters
%u - Unsigned decimal integer
%x - Unsigned hexadecimal integer
%X - Unsigned hexadecimal integer (capital letters)
%p - Pointer address
%n - Nothing printed
The code is printing a 0, because you are using the format tag %d, which represents Signed decimal integer (http://devdocs.io).
Could you please try
void main() {
clrscr();
float f=3.3;
/* In printf() I intentionaly put %d format specifier to see what type of output I may get */
printf("value of variable a is: %f",f);
getch();
}
I tried to print character as a float in printf and got output 0. What is the reason for this.
Also:
char c='z';
printf("%f %X",c,c);
is giving some weird output for hexadecimal while output is correct when I do this:
printf("%X",c);
why is it so?
The printf() function is a variadic function, which means that you can pass a variable number of arguments of unspecified types to it. This also means that the compiler doesn't know what type of arguments the function expects, and so it cannot convert the arguments to the correct types. (Modern compilers can warn you if you get the arguments wrong to printf, if you invoke it with enough warning flags.)
For historical reasons, you can not pass an integer argument of smaller rank than int, or a floating type of smaller rank than double to a variadic function. A float will be converted to double and a char will be converted to int (or unsigned int on bizarre implementations) through a process called the default argument promotions.
When printf parses its parameters (arguments are passed to a function, parameters are what the function receives), it retrieves them using whatever method is appropriate for the type specified by the format string. The "%f" specifier expects a double. The "%X" specifier expects an unsigned int.
If you pass an int and printf tries to retrieve a double, you invoke undefined behaviour.
If you pass an int and printf tries to retrieve an unsigned int, you invoke undefined behaviour.
Undefined behaviour may include (but is not limited to) printing strange values, crashing your program or (the most insidious of them all) doing exactly what you expect.
Source: n1570 (The final public draft of the current C standard)
You need to use a cast operator like this:
char c = 'z';
printf("%f %X", (float)c, c);
or
printf("%f %X", (double)c, c);
In Xcode, if I do not do this, I get the warning:
Format specifies specifies 'double' but the argument has type 'char', and the output is 0.000000.
I tried to print character as a float in printf and got output 0. What is the reason for this.
The question is, what value did you expect to see? Why would you expect something other than 0?
The short answer to your question is that the behavior of printf is undefined if the type of the argument doesn't match the conversion specifier. The %f conversion specifier expects its corresponding argument to have type double; if it isn't, all bets are off, and the exact output will vary.
To understand the floating point issue, consider reading: http://en.wikipedia.org/wiki/IEEE_floating_point
As for hexadecimal, let me guess.. the output was something like... 99?
This is because of encodings.. the machine has to represent information in some format, and usually that format entails either giving meanings to certain bits in a number, or having a table of symbols to numbers, or both
Floating points are sometimes represented as a (sign,mantissa,exponent) triplet all packed in a 32 or 64 bit number - characters are sometimes represented in a format named ASCII, which establishes which number corresponds to each character you type
Because printf, like any function that work with varargs, eg: int foobar(const char fmt, ...) {} tries to interpret its parameter to certain type.
If you say "%f", then pass c (as a char), then printf will try to read a float.
You can read more here: var_arg (even if this is C++, it still applies).
I tried to print character as a float in printf and got output 0. What is the reason for this.
Also:
char c='z';
printf("%f %X",c,c);
is giving some weird output for hexadecimal while output is correct when I do this:
printf("%X",c);
why is it so?
The printf() function is a variadic function, which means that you can pass a variable number of arguments of unspecified types to it. This also means that the compiler doesn't know what type of arguments the function expects, and so it cannot convert the arguments to the correct types. (Modern compilers can warn you if you get the arguments wrong to printf, if you invoke it with enough warning flags.)
For historical reasons, you can not pass an integer argument of smaller rank than int, or a floating type of smaller rank than double to a variadic function. A float will be converted to double and a char will be converted to int (or unsigned int on bizarre implementations) through a process called the default argument promotions.
When printf parses its parameters (arguments are passed to a function, parameters are what the function receives), it retrieves them using whatever method is appropriate for the type specified by the format string. The "%f" specifier expects a double. The "%X" specifier expects an unsigned int.
If you pass an int and printf tries to retrieve a double, you invoke undefined behaviour.
If you pass an int and printf tries to retrieve an unsigned int, you invoke undefined behaviour.
Undefined behaviour may include (but is not limited to) printing strange values, crashing your program or (the most insidious of them all) doing exactly what you expect.
Source: n1570 (The final public draft of the current C standard)
You need to use a cast operator like this:
char c = 'z';
printf("%f %X", (float)c, c);
or
printf("%f %X", (double)c, c);
In Xcode, if I do not do this, I get the warning:
Format specifies specifies 'double' but the argument has type 'char', and the output is 0.000000.
I tried to print character as a float in printf and got output 0. What is the reason for this.
The question is, what value did you expect to see? Why would you expect something other than 0?
The short answer to your question is that the behavior of printf is undefined if the type of the argument doesn't match the conversion specifier. The %f conversion specifier expects its corresponding argument to have type double; if it isn't, all bets are off, and the exact output will vary.
To understand the floating point issue, consider reading: http://en.wikipedia.org/wiki/IEEE_floating_point
As for hexadecimal, let me guess.. the output was something like... 99?
This is because of encodings.. the machine has to represent information in some format, and usually that format entails either giving meanings to certain bits in a number, or having a table of symbols to numbers, or both
Floating points are sometimes represented as a (sign,mantissa,exponent) triplet all packed in a 32 or 64 bit number - characters are sometimes represented in a format named ASCII, which establishes which number corresponds to each character you type
Because printf, like any function that work with varargs, eg: int foobar(const char fmt, ...) {} tries to interpret its parameter to certain type.
If you say "%f", then pass c (as a char), then printf will try to read a float.
You can read more here: var_arg (even if this is C++, it still applies).
As of the printf function is concerned, I understand the following from few references and experiments.
When we try to print an integer value with format specifiers that are used for float (or) double and vice the versa the behaviour is unpredictable.
But it is possible to use %c to print the character equivalent of the integer value. Also using of %d to print ASCII value (integer representations) of character is acceptable.
Similarly, what is the behaviour of scanf, if there is a mismatch of format specifier and the arguements passed to scanf. Does the standards define it?
Variadic arguments (those matching the ellipsis, ...) are default-promoted. That means that all shorter integral types are promoted to int (or unsigned, as appropriate). There's no difference between integers and characters (I believe). The difference between %d and %c in printf is merely how the value is formatted.
scanf is a different kettle of fish. All the arguments you pass are pointers. There's no default-promotion among pointers, and it is crucial that you pass the exact format specifier that matches the type of the pointee.
In either case, if your format specifier doesn't match the supplied argument (e.g. passing an int * to a %p in printf), the result is undefined behaviour, which is far worse than being "unpredictable" -- it means your program is simply ill-formed.
printf and scanf are confusing, because they're pretty special and unusual functions. Both of them accept a variable number of arguments. And this means that the rules for matching the types of the arguments, and the automatic conversions that might happen, are different than for other functions.
For most functions, the compiler knows exactly what type(s) of arguments(s) are expected. For example, if you call
#include <math.h>
int i = 144;
printf("%f\n", sqrt(i));
it works fine. The sqrt function expects an argument of type double, but the compiler knows this, so it can insert an automatic conversion, just as if you had written
printf("%f\n", sqrt((double)i));
(Footnote: The compiler knows about sqrt's expected argument type from the function prototype found in <math.h>.)
But printf accepts a variable number of arguments, of any types. You can pass just about anything, as long as the format specifiers match:
int i1 = 12, i2 = 34;
float f1 = 56.78, f2 = 9.10;
printf("%d %d %f %f\n", i1, i2, f1, f2);
printf("%f %f %d %d\n", f1, f2, i1, i2);
But that's the key: as long as the format specifiers match. In a call to a function with a variable number of arguments, like printf, the compiler does not attempt (it's not even allowed to attempt) to convert each argument to the type expected by the corresponding format specifier. So if there are gross mismatches, like trying to use %f to print an integer, it doesn't work, and in fact crazy things can happen.
But, just to keep things interesting, when you call a function that takes a variable number of arguments, like printf, there's another set of conversions that are automatically performed. They're called the default argument promotions. Basically, anything of type char or short is automatically converted ("promoted") to int, and anything of type float automatically converted to double. So you can get away with some mismatches: you can print a char or a short using %d, and you can print either a float or a double using %f. And since char is always promoted to int, that means %c is actually going to receive an int, and this means you can pass a regular int and print it with %c, also.
But it's easy to get this stuff wrong, especially since we're used to the compiler converting everything properly for us when we call other functions, like sqrt. So, a good compiler will peek at the format string, and use it to predict what types of arguments you ought to pass, and if you're passing something wrong, the compiler can issue a warning. If your compiler isn't issuing such warnings, it would be a good idea to figure out how to enable them, or if not, perhaps get a better compiler.
And then we come to scanf. scanf also accepts a variable number of arguments, which are supposed to match the specifiers on the format string. However, for scanf, all of the arguments you pass are pointers, to variables of yours which you're asking scanf to fill in with the values it reads. And it turns out this means that no automatic conversions are possible, and you must pass all arguments as pointers of exactly the right type. Here is a table listing some of them:
specifier
corresponding argument
%c
pointer to char
%hd
pointer to short
%d
pointer to int
%ld
pointer to long
%f
pointer to float
%lf
pointer to double
%s
pointer to char [note]
So there's no automatic conversion from char and short to int like there is for printf, and there's no automatic conversion from float to double If you're reading a float you have to use %f, and if you're reading a double you have to use %d.
Again, though, a good compiler will warn you about any mismatches, and it's a very good idea to seek out and pay attention to those warnings!
There is one "conversion" that happens automatically when you call scanf, but it has nothing to do with scanf. If you're using %s to read a string, you're supposed to pass an argument of type pointer-to-char, although it has to be a pointer to some number of contiguous characters, because scanf probably isn't going to read a single character; it's probably going to read a string of several characters. So it's pretty common to pass scanf an array of characters, and this is okay, because whenever you use an array in an expression in C, like when you pass it to a function (like scanf), the value that gets used is a pointer to the array's first element, which works just fine, and is what scanf is expecting. That is, both
char *p = malloc(10);
scanf("%9s", p);
and
char a[1-];
scanf("%9s", a);
will work. (And note that this is the one case where you do not need to use a & on a variable you pass to scanf.)