I'm just wondering why am I getting a 0 value when I try to print the addition of a char and an integer value. My code is as follows:
int y;
y = 10;
char z;
z = '9';
printf("%f", z + y);
This call of printf
printf("%f", z + y);
invokes undefined behavior because you are using the incorrect conversion specifier %f with an object of the type int.
You need to cast the argument like for example
printf( "%f", ( double )( z + y ) );
or
printf( "%f", ( float )( z + y ) );
though in the last case the argument will be promoted to the type double due to the default argument promotions.
Most of the time, when you call a function, and you pass the wrong type of argument, C automatically converts it for you. For example, if I write
#include <math.h>
int i = sqrt(144);
printf("%d\n", i);
this works, and prints 12. It works even though the sqrt function actually wants an argument of type double — because the compiler knows that, and automatically converts my int argument 144 to double before passing it to sqrt. (There's also a conversion on the way back, because sqrt returns a double, which has to be converted back to int before assigning to i.)
But the printf function itself is a big, giant exception to this rule. In your code, you had
printf("%f", z + y);
Now, you and I both know that %f wants a double, but this is not something that, traditionally, the C language can know about. As far as the C language is concerned, the printf function takes one argument of type const char * (that is, a string), and then possibly some number of other arguments, depending on the particular %-sequences that are found in the format string at run-time. So the compiler makes only a half-hearted attempt, converting them to a few, common types and then passing them on to printf to do the rest. In your example, since z is a char and y is an int, z + y will be an int, and that's what gets passed to printf. By the time printf is chewing on the format string and finds the format specifier %f, it has no way of knowing what type of argument was actually passed, so it can't even try to do any conversions of its own. All it can do is assume that you actually passed a double — and, since you didn't, you get a meaningless value printed instead.
Now, although as I've just explained, the compiler didn't traditionally have any license to try to convert printf arguments to the proper type, modern compilers typically do take a peek at the format string, if they can, and check that things are going to work properly at run time. For example, when I run your code through one of my compilers, I get warning: format specifies type 'double' but the argument has type 'int'. If your compiler is not giving you warnings like this, you might want to find out if there's a way to enable them, because they're obviously super handy.
As already pointed out in the comments section, it is your responsibility to ensure that the format string and the function arguments match. In your case, they do not match. The result of the expression z + y is of type int, but you are using the %f conversion specifier in the format string, which is only valid for the data types float and double (float gets promoted to double).
As pointed out in the comments section, you have two options to fix this:
change the format string to expect an argument of type int, or
cast the argument to double or float
The solution using option #1 would look like this:
Change the line
printf("%f", z + y);
to
printf("%d", z + y);
The solution using option #2 would look like this:
Change the line
printf("%f", z + y);
to
printf("%f", (double) (z + y) );
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.
I am currently learning about C language data type and I try to print a double variable the compiler suggested me to use fl after I type '%', and I got 1 number in the end of precision decimal line. Compare to %lf it will print six precision decimals in total
double num=12322;
printf("%lf",num);// result is 12322.000000
printf("%fl",num);// result is 12322.0000001
I've searched plenty of place but mostly the difference between %f and %lf is frequently asked. Is my situation could possiply the same?
In this call of printf
printf("%lf",num);// result is 12322.000000
the length modifier l in the conversion specifier %lf has no effect.
From the C Standard (7.21.6.1 The fprintf function)
7 The length modifiers and their meanings are:
l (ell) Specifies that a following d, i, o, u, x, or X conversion
specifier applies to a long int or unsigned long int argument; that a
following n conversion specifier applies to a pointer to a long int
argument; that a following c conversion specifier applies to a wint_t
argument; that a following s conversion specifier applies to a pointer
to a wchar_t argument; or has no effect on a following a, A, e, E,
f, F, g, or G conversion specifier.
In this call of printf
printf("%fl",num);// result is 12322.0000001
where in the comment there shall be written the letter 'l' instead of the number 1 as you think
// result is 12322.000000l
^^^
the format string "%fl" means that after outputting an object of the type double due to the conversion specification %f there will be outputted the letter 'l'.
Pay attention to that with the conversion specifier f there can be used one more letter 'l' that is the upper case letter 'L'. In this case the conversion specification %Lf serves to output objects of the type long double.
I think you actually have a typo in your output....
double num=12322;
printf("%lf",num);// result is 12322.000000
printf("%fl",num);// result is 12322.0000001
is actually
double num=12322;
printf("%lf",num);// result is 12322.000000
printf("%fl",num);// result is 12322.000000l
The C standard says that the float is converted to a double when passed to a variadic function, so %lf and %f are equivalent; %fl is the same a %f... with an l after it.
There are two correct ways of printing a value of type double:
printf("%f", num);
or
printf("%lf", num);
These two have exactly the same effect. In this case, the "l" modifier is effectively ignored.
The reason they have the same effect is that printf is special. printf accepts a variable number of arguments, and for such functions, C always applies the default argument promotions. This means that all integer types smaller than int are promoted to int, and float is promoted to double. So if you write
float f = 1.5;
printf("%f\n", f);
then f is promoted to double before being passed. So inside printf, it always gets a double. So %f will never see a float, always a double. So %f is written to expect a double, so it ends up working for both float and double. So you don't need a l modifier to say which. But that's kind of confusing, so the Standard says you can put the l there if you want to — but you don't have to, and it doesn't do anything.
(This is all very different, by the way, from scanf, where %f and %lf are totally different, and must be explicitly matched to arguments of type float * versus double *.)
I have no idea why your IDE complained about (put a red line under) %lf, and I have no idea what it meant by suggesting, as you said,
fl, lg, l, f,
elf, Alf, ls, sf,
if, la, lo, of
Some of those look they might be nonstandard, system-specific extensions, but some (especially fl) are nonsense. So, bottom line, it sounds like your IDE's suggestion was confusing, unnecessary, and quite possibly wrong.
I'm trying to run the following code for a demonstration of how conversion works.
#include <stdio.h>
int main()
{
int x=5;
int y=2;
float z;
printf("x=%d\n", x);
printf("y=%d\n", y);
//Doing division as it is
z= x/y;
printf("With no preliminar assignment: (z=x/y)\n");
printf("\"z\" is: %d (integer) or %lf (double) or %f(float)\n\n\n", z, z, z);
//Doing assignment before division
printf("With the assignment: (z=x)\n");
z=x;
printf("\"z\" before division is:");
printf("%d (integer) or %lf (double) or %f(float)\n", z, z, z);
//Doing division after assignment
z/=y;
printf("\"z\" after division with assignment: (z=z/y)");
printf(" is: %d (integer) or %lf (double) or %f(float)\n", z, z, z);
return 0;
}
The OUTPUT is:
x=5
y=2
With no preliminar assignment: (z=x/y)
"z" is: 0 (integer) or 0.000000 (double) or 0.000000(float)
With the assignment: (z=x)
"z" before division is:0 (integer) or 0.000000 (double) or 0.000000(float)
"z" after division with assignment: (z=z/y) is: 0 (integer) or 0.000000 (double) or 0.000000(float)
This leave me with a doubt, also because my professor at University wrote the following code:
int x=5;
int y=2;
float z;
int main (void) {
z = x / y;
return 0;
}
And for him, z will assume 2.0 (Which is logically correct, but not in printf).
So my final question is, why am I having 0 as result in all the printf?
(I would like to not to use type casting operator)
printf(), as many variadic functions, use a format string to tell to the function which kind of parameters expect on the call stack, but this doesn't imply that any conversion is actuated on such parameters based on the format string.
Anyway any decent compiler will warn you about the format/parameters type mismatch, this means that you deliberately ignored them..
Probably you are making a confusion between argument promotions and format specifier.
In variable arguments functions the parameters not explicitly defined, those identified by ..., are handled in a standard way as described in C standard ISO/IEC 9899:201x, §6.5.2.2 Function calls. In subparagraph 6 we read:
If the expression that denotes the called function has a type that
does not include a prototype, the integer promotions are performed on
each argument, and arguments that have type float are promoted to
double. These are called the default argument promotions.
If the
number of arguments does not equal the number of parameters, the
behavior is undefined. If the function is defined with a type that
includes a prototype, and either the prototype ends with an ellipsis
(, ...) or the types of the arguments after promotion are not
compatible with the types of the parameters, the behavior is
undefined. If the function is defined with a type that does not
include a prototype, and the types of the arguments after promotion
are not compatible with those of the parameters after promotion, the
behavior is undefined, except for the following cases:
one promoted
type is a signed integer type, the other promoted type is the
corresponding unsigned integer type, and the value is representable in
both types;
both types are pointers to qualified or unqualified > versions of a character type or void.
So if you want have a meaningful output you must explicetely convert parameters as in:
printf(" is: %d (integer) or %lf (double) or %f(float)\n", (int)z, z, z);
Note that only the cast to int is due, leaving the other 2 entries to default promotion that will convert float to double satisfying what the function expect based on the format string. Without the explicit cast the compiler will promote the variable z from float to double, as per the default argument promotion rules, while the printf() code will try to access it as an int.
The problem of values all zero in your code is due to the mismatch in the parameters size int/double that broken the stack unwrap.
why am I having 0 as result in all the printf?
You have an incomplete understanding of the significance of formatting directives in a printf format string. Above all else they convey to printf the data type of their corresponding arguments, which are not otherwise known to printf. They also specify details of how to format the value, but that is secondary to the question of how to interpret the argument list. If the directives do not correspond correctly to the actual argument types, then the resulting behavior is wholly undefined. Certainly printf can produce surprising output in such cases,* but in principle, anything could happen.
Thus a statement such as this ...
printf("\"z\" is: %d (integer) or %lf (double) or %f(float)\n\n\n", z, z, z);
... where conversion directives specify different, incompatible types for the same value, is always incorrect. One way to correct it would be to convert the arguments to the correct types, like so:
printf("\"z\" is: %d (integer) or %lf (double) or %f(float)\n\n\n", (int) z, (double) z, z);
But that's not particularly useful for your apparent purpose. It appears that all the conversions you're actually interested in happen before or during each assignment to z, so nothing is gained by considering the results of afterward converting that result to other data types. This, then, would be a better correction:
printf("\"z\" is: %f(float)\n\n\n", z);
Alternatively, to separate the effects of conversion during assignment from the effects of conversion during arithmetic computation, you could perform different assignments to variables of the different types of interest. For example,
int x = 5;
int y = 2;
int zi;
double zd;
float zf;
// ...
zi = x / y;
zd = x / y;
zf = x / y;
// ...
printf("\"z\" is: %d (integer) or %lf (double) or %f(float)\n\n\n", zi, zd, zf);
* This is the answer to the actual question posed.
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.
I am not able to understand why
float x = (4+2%-8);
printf("%f\n", x);
prints 6.000000 and
printf("%f\n", (4+2%-8));
prints 0.000000. Any information will be helpful.
Regards.
The expression (4 + 2 % -8) produces an integer and you are trying to print a float (and they don't match).
In the first case the integer is converted to float (because of the assignment) so later on the printf works because the value is in a format %f expects.
Try this:
printf("%f\n", (4.0 + 2 % -8));
^
It's because here:
float x = (4+2%-8);
The (4+2%-8) is of type int but is converted to float because that's the type of x. However, here:
printf("%f\n", (4+2%-8));
No cast is performed so you pass an int where it expects a float giving you a garbage value. You can fix this with a simple cast:
printf("%f\n", (float)(4+2%-8));
In the first snippet the resulting int value is implicitly converted to float due to assignment, in the second snippet you are lying to the compiler: you tell it to expect a value of type double but "send" a value of type int instead.
Do not lie to the compiler. It will get its revenge.
Note that the printf conversion specifier "%f" expects a value of type double, but "sending" a float is ok because that value is automagically converted to double before the function is called.