C 's format specifier - c

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.

Related

why printf behaves differently when we try to print float as a hexadecimal? [duplicate]

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

c-behaviour of printf("%d", <double>) [duplicate]

This question already has answers here:
Given the state of the stack and registers, can we predict the outcome of printf's undefined behavior
(2 answers)
Closed 6 years ago.
Why does this code prints nonsense values? If it makes sense then what is it?
printf("%d\n", 5.0 / 4);
By the way, I know about format specifiers I should be using %f instead of %d. but I want to know what c actually does.
Strangely, every time I run the compiled program, it prints a different thing. doesn't it have to be deterministic?
As far as I could observe, this code prints a similar thing:
float c;
printf("%d\n", &c);
are they any related?
and when i tried:
float c;
printf("%d\n%d\n", c, &c);
There is a constant 252 between those two values. 256 - sizeof(float) maybe?
and declaring c as a double makes the difference 0.
Thanks in advance!
UPDATE: writing the same code on different machines yielded different results.(252 being 56. former is a 64-bit ubuntu machine and latter is 64-bit OS X)
printf is unusual in that it has no single function signature. In other words, there's no mechanism to automatically take the actual arguments you pass and convert them into the type that's expected. Whatever you try to pass, gets passed. If the type you pass does not match the type expected by the corresponding format specifier, you get nonsense.
Furthermore, if the mismatched types you're passing versus what the format specifiers are expecting have different sizes, printf can end up popping random garbage off the stack, that has nothing to do with what you thought you passed.
You asked, "doesn't it have to be deterministic?", and the answer there is a very emphatic "NO"! By passing the wrong type of value to printf, you have invoked undefined behavior, which means that anything can happen, and it very definitely does not have to be the same thing twice.
(Even though they're not required to, some compilers peek at the format string and try to check the values you passed against the values that are expected. For example, under gcc, your first code fragment gets the warning "format ‘%d’ expects type ‘int’, but argument 2 has type ‘double’". But I don't know of a compiler that will try to do conversions to "fix" the arguments.)

Why printf("%.1f", 1) output 0.0

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!

why printf behaves differently when we try to print character as a float and as a hexadecimal?

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

Puzzled about printf output

While using printf with %d as format specifier and giving a float as an argument e.g, 2.345, it prints 1546188227. So, I understand that it may be due to the conversion of single point float precision format to simple decimal format. But when we print 2.000 with the %d as format specifier, then why it prints 0 only ?
Please help.
Format specifier %d can only be used with values of type int (and compatible types). Trying to use %d with float or any other types produces undefined behavior. That's the only explanation that truly applies here. From the language point of view the output you see is essentially random. And you are not guaranteed to get any output at all.
If you are still interested in investigating the specific reason for the output you see (however little sense it makes), you'll have to perform a platform-specific investigation, because the actual behavior depends critically on various implementation details. And you are not even mentioning your platform in your post.
In any case, as a side note, note that it is impossible to pass float values as variadic arguments to variadic functions. float values in such cases are always converted to double and passed as double. So in your case it is double values you are attempting to print. Behavior is still undefined though.
Go here, enter 2.345, click "rounded". Observe 64-bit hex value: 4002C28F5C28F5C3. Observe that 1546188227 is 0x5c28f5c3.
Now repeat for 2.00. Observe that 64-bit hex value is 4000000000000000
P.S. When you say that you give a float argument, what you apparently mean is that you give a double argument.
Here what ISO/IEC 9899:1999 standard $7.19.6 states:
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.
If you're trying to make it print integer values, cast the floats to ints in the call:
printf("ints: %d %d", (int) 2.345, (int) 2.000);
Otherwise, use the floating point format identifier:
printf("floats: %f %f", 2.345, 2.000);
When you use printf with wrong format specifier for the corresponding argument, the result is undefined behavior. It could be anything and may differ from one implementation to another. Only correct use of format specified has defined behavior.
First a small nitpick: The literal 2.345 is actually of the type double, not float, and besides, even a float, such as the literal 2.345f, would be converted to double when used as an argument to a function that takes a variable number of arguments, such as printf.
But what happens here is that the (typically) 64 bits of the double value is sent to printf, and then it interprets (typically) 32 of those bits as an integer value. So it just happens that those bits were zero.
According to the standard, this is what is called undefined behavior: The compiler is allowed to do anything at all.

Resources