Arithmetic expression as printf arg - c

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.

Related

Which placeholder should I use in and why?

Why the code only works when I use the %lf or %f place holder (second placeholder), but its printing 0 when I use %d?
#include <stdio.h>
void main()
{
long id;
id = 123456789;
double Hourly;
Hourly = 30;
int HoursAday, daysAweek, Fired, Hired;
HoursAday = 8; daysAweek = 5; Fired = 2021; Hired = 2019;
printf("bob, id: \"%d\" should get %lf", id, (Hourly * HoursAday * daysAweek) * (Fired - Hired));
The type of (Hourly * HoursAday * daysAweek) * (Fired - Hired) is double so the correct specifier is %lf. Because of variadic arguments default conversions the code will also work with %f (*). But %d is undefined behavior.
Also, the correct specifier for id (which is of type long) is %ld. %d is undefined behavior.
See the documentation for printf: https://en.cppreference.com/w/c/io/fprintf
(*) A float variadic argument always gets converted to double. So the printf family of functions will never receive a float, they will always receive a double. That's why %f and %lf are for practical reasons equivalent.
This expression
(Hourly * HoursAday * daysAweek) * (Fired - Hired)
has the type double due to the usual arithmetic conversions because the variable Hourly has the type double. That is if one operand has the type double and other operand has an integer type in a binary operation then the operand with the integer type is converted to the type double.
Using the wrong conversion specifier %d designed to output objects of the type int with an object of the type double invokes undefined behavior.
Pay attention to that in this conversion specifier %lf the length modifier l has no effect. So it is enough to use %f.

Printing addition of char and integer value as float

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) );

Conversion type in printf (with no casting operator)

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.

why result of (double + int) is 0 (C language)

result of
printf("%d\n", 5.0 + 2);
is 0
but
int num = 5.0 + 2;
printf("%d\n", num);
is 7
What's the difference between the two?
The result of 5.0 + 2 is 7.0 and is of type double.
The "%d" format is to print int.
Mismatching format specification and argument type leads to undefined behavior.
To print a float or double value with printf you should use the format "%f".
With
int num = 5.0 + 2;
you convert the result of 5.0 + 2 into the int value 7. Then you print the int value using the correct format specifier.
In all expressions, every operand has a type. 5.0 has type double. 2 has type int.
Whenever a double and an integer are used as operands of the same operator, the integer is silently converted to a double before calculation. The result is of type double.
And so you pass double to printf, but you have told it to expect an int, since you used %d. The result is a bug, the outcome is not defined.
But in case of int num = 5.0 + 2;, you first get a result as double, 7.0. Then force a conversion back to int. That code is equivalent to:
int num = (int)((double)5.0 + (double)2);
More details here: Implicit type promotion rules
The result of expression 5.0 + 2 is of type double, since at least one of the two operands of operator + here is a floating point / double value (so the other one will be converted to double before adding).
If you write printf("%d\n", 5.0 + 2), you will pass a floating point value where the format specifier actually expects an int. This mismatch is undefined behaviour, and the 0 you receive could be something else (another number, a crash, a .... what ever), too.
int num = 5.0 + 2, in contrast, will convert the double-value resulting from 5.0 + 2 back to an integral value (discarding any fractional part). So the value of num will be 7 and will be - since num is an integral type - valid in conjunction with format specifier %d then.
5.0+2 is typed double.
The compiler warning for
int main() { return _Generic(5.0 + 2, struct foo: 0); }
should tell you as much if
int main() { return _Generic(5.0 + 2, double: 5.0+2); }
compiling without error doesn't.
Matching "%d" with a double in printf results in undefined behavior.
Any result is legal, including your harddrive getting erased (unlikely to happen unless your program already has such functionality somewhere in it; if it does, UB can well result it it being inadvertently invoked).
The usual arithmetic conversions are implicitly performed to cast their values to a common type. The compiler first performs integer promotion; if the operands still have different types, then they are converted to the type that appears highest in the following hierarchy -
In int num = 5.0 + 2; this code snippet you are adding a float with integer and storing back to integer again. So, c automatically casts the result into integer to store in an integer type variable. So, while printing using %d, it prints fine.
But, in printf("%d\n", 5.0 + 2); this code snippet, the addition is casted into floating point number as float has higher priority over integer, but you are printing it using %d. Here mismatch of format specifier causing the unexpected result.

Why the division of two integers return 0.00? [duplicate]

This question already has answers here:
printf("%f", aa) when aa is of type int [duplicate]
(2 answers)
Closed 7 years ago.
Every time I run this program I get different and weird results. Why is that?
#include <stdio.h>
int main(void) {
int a = 5, b = 2;
printf("%.2f", a/b);
return 0;
}
Live Demo
printf("%.2f", a/b);
The output of the division is again of type int and not float.
You are using wrong format specifier which will lead to undefined behavior.
You need to have variables of type float to perform the operation you are doing.
The right format specifier to print out int is %d
In your code, a and b are of type int, so the division is essecntially an integer division, the result being an int.
You cannot use a wrong format specifier anytime. %f requires the corresponding argument to be of type double. You need to use %d for int type.
FWIW, using wrong format specifier invokes undefined behaviour.
From C11 standard, chapter §7.21.6.1, fprintf()
If any argument is not the correct type for the corresponding conversion specification, the behavior is undefined.
If you want a floating point division, you need to do so explicitly by either
promoting one of the variable before the division to enforce floating point division, result of which will be of floating point type.
printf("%.2f", (float)a/b);
use float type for a and b.
You need to change the type as float or double.
Something like this:
printf("%.2f", (float)a/b);
IDEONE DEMO
%f format specifier is for float. Using the wrong format specifier will lead you to undefined behavior. The division of int by an int will give you an int.
Use this instead of your printf()
printf("%.2lf",(double)a/b);

Resources