Unexpected result in C program - c

Can you please explain the output of this C program? I guess that the problem is with the stack getting corrupt during printf("%d\n",t); function call because I'm pushing a float but reading an int. I'm not sure.
#include <stdio.h>
int main()
{
long x;
float t;
scanf("%f",&t);
printf("%d\n",t);
x=30;
printf("%f\n",x);
{
x=9;
printf("%f\n",x);
{
x=10;
printf("%f\n",x);
}
printf("%f\n",x);
}
x==9;
printf("%f\n",x);
}
And the output
$ ./a.out
20.39
0
20.389999
20.389999
20.389999
20.389999
20.389999
$

What happens is that you lie to the compiler ... first you tell it you are going to send an int to printf but you send a float instead, and then you tell it you are going to send a double but you send a long instead.
Don't do that. Don't lie to the compiler.
You have invoked Undefined Behaviour. Anything can happen. Your program might corrupt the stack; it might output what you expect; it might make lemon juice come out of the USB port; it might make demons fly out of your nose; ...

You are using the wrong format specifier to print long. Use format specifier %ld instead.
Results
printf("%f\n",x);
// ^ change this to %ld

What actually happens is:
Your float is 4 bytes, your long is 4 bytes, your double is 8 bytes.
You pass a float through ellipsis - it gets converted to a double. 8 bytes on stack.
You pass a long through ellipsis - 4 bytes on stack.
printf parses 8 bytes on stack (float specifier) as a double. This double will consist of the "important" part of the old double on stack, and a slight variation in the least significant part (your long).
Default %f output truncates the value, you don't see the variation.
Change all your %f to e.g. %.20f to see how the long affects the double.

printf("%d\n",t);
Using incorrect format specifier in printf invokes undefined behaviour.
Use %f for printing float and double and %ld for printing long
C99 clearly says (wrt printf and fprintf)
If a conversion specification is invalid, the behavior is undefined. If any argument is
not the correct type for the corresponding conversion specification, the behavior is
undefined.

Related

The problem about printf function to "output float with %d" in C

I am a newbie to the C language. When I was learning floating point numbers today, I found the following problems.
float TEST= 3.0f;
printf("%x\n",TEST);
printf("%d\n",TEST);
first output:
9c9e82a0
-1667333472
second output:
61ea32a0
1642738336
As shown above, each execution will output different results. I have checked a lot of IEEE 754 format and still don't understand the reasons. I would like to ask if anyone can explain or provide keywords for me to study, thank you.
-----------------------------------Edit-----------------------------------
Thank you for your replies. I know how to print IEEE 754 bit pattern. However, as Nate Eldredge, chux-Reinstate Monica said, using %x and %d in printf is undefined behavior. If there is no floating point register in our device, how does it work ? Is this described in the C99 specification?
Most of the time, when you call a function with the "wrong kind" (wrong type) of argument, an automatic conversion happens. For example, if you write
#include <stdio.h>
#include <math.h>
printf("%f\n", sqrt(144));
this works just fine. The compiler knows (from the function prototype in <math.h>) that the sqrt function expects an argument of type double. You passed it the int value 144, so the compiler automatically converted that int to double before passing it to sqrt.
But this is not true for the printf function. printf accepts arguments of many different types, and as long as each argument is right for the particular % format specifier it goes with in the format string, it's fine. So if you write
double f = 3.14;
printf("%f\n", f);
it works. But if you write
printf("%d\n", f); /* WRONG */
it doesn't work. %d expects an int, but you passed a double. In this case (because printf is special), there's no good way for the compiler to insert an automatic conversion. So, instead, it just fails to work.
And when it "fails", it really fails. You don't even necessarily get anything "reasonable", like an integer representing the bit pattern of the IEEE-754 floating-point number you thought you passed. If you want to inspect the bit pattern of a float or double, you'll have to do that another way.
If what you really wanted to do was to see the bits and bytes making up a float, here's a completely different way:
float test = 3.14;
unsigned char *p = (unsigned char *)&test;
int i;
printf("bytes in %f:", test);
for(i = 0; i < sizeof(test); i++) printf(" %02x", p[i]);
printf("\n");
There are some issues here with byte ordering ("endianness"), but this should get you started.
To print hex (ie how it is represented in the memory) representation of the float:
float TEST= 3.0f;
int y=0;
memcpy(&y, &TEST, sizeof(y));
printf("%x\n",y);
printf("%d\n",y);
or
union
{
float TEST;
int y;
}uf = {.y = 0};
uf.TEST = 3.0f;
printf("\n%x\n",(unsigned)uf.y);
printf("%d\n",uf.y);
Both examples assuming sizeof(float) <= sizeof(int) (if they are not equal I need to zero the integer)
And the result (same for both):
40400000
1077936128
As you can see it is completely different from your one.
https://godbolt.org/z/Kr61x6Kv3

I get previous float value when I am printing new value

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.

Why is this code printing 0?

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

Different output every time in c?

I am trying to learn C and am very confused already.
#include <stdio.h>
int main(void)
{
int a = 50000;
float b = 'a';
printf("b = %f\n", 'a');
printf("a = %f\n", a);
return 0;
}
The above code produces a different output each time with gcc. Why?
You pass an int value ('a') for a %f format expecting a float or a double. This is undefined behavior, which can result in different output for every execution of the same program. The second printf has the same problem: %f expects a float or double but you pass an int value.
Here is a corrected version:
#include <stdio.h>
int main(void) {
int a = 50000;
float b = 'a';
printf("a = %d\n", a);
printf("b = %f\n", b);
printf("'a' = %d\n", 'a');
return 0;
}
Output:
a = 50000
b = 97.000000
'a' = 97
Compiling with more warnings enabled, with command line arguments -Wall -W -Wextra lets the compiler perform more consistency checks and complain about potential programming errors. It would have detected the errors in the posted code.
Indeed clang still complains about the above correction:
clang -O2 -std=c11 -Weverything fmt.c -o fmt
fmt.c:8:24: warning: implicit conversion increases floating-point precision: 'float' to 'double' [-Wdouble-promotion]
printf("b = %f\n", b);
~~~~~~ ^
1 warning generated.
b is promoted to double when passed to printf(). The double type has more precision than the float type, which might output misleading values if more decimals are requested than the original type afforded.
It is advisable to always use double for floating point calculations and reserve the float type for very specific cases where it is better suited, such as computer graphics APIs, some binary interchange formats...
From implementation standpoint, passing floating point numbers (that what %f expects) as variable argument lists (that is what ... means in printf prototype) and integers (that is what 'a' is, specifically of type int) may use different registers and memory layout.
This is usually defined by ABI calling conventions. Specifically, in x86_64, %xmm0 will be read by printf (with unitialized value), but gcc will fill %rdi in printf call.
See more in System V Application Binary Interface AMD64 Architecture Processor Supplement, p. 56
You should note that C is a very low-level language which puts a lot of confusing cases (including integer overflows and underflows, unitialized variables, buffer overruns) on shoulders of implementation. That allows to gain maximum performance (by avoiding lots of checks), but leaves to errors such as this error.
The %f specifier needs to be matched by a floating-point parameter (float or double), you're giving it ints instead. Not matching the type is undefined behaviour, meaning it could do anything, including printing different results everytime.
Hope this helped, good luck :)
Edit: Thanks chqrlie for the clarifications!
Unpredictable behavior.
When you try to print value using mismatch format specifier, compiler give an unpredictable output.The behavior on using %f as the format specifier for an char and int is undefined.
Use correct format specifier in your program according yo data type:
printf("%d\n", 'a'); // print ASCII value
printf("%d\n", a);
First of all, gcc should give a warning for the above code. This is because of the mismatch in the format specifier.
Mismatched formatting (printf() as well as scanf()) will give unpredictable behavior in C. This is in spite of the fact that gcc is expected to take care possible type conversions like int to float implicitly.
Here is are two nice references.
https://stackoverflow.com/a/1057173/4954434
https://stackoverflow.com/a/12830110/4954434
Following will work as expetced.
#include <stdio.h>
int main(void)
{
int a = 50000;
float b = 'a';
printf("b = %f\n", (float)'a');
printf("a = %f\n", (float)a);
return 0;
}
The main difficult you are having is the data type you are using.
When you create a variable you are telling the size the memory will have to reserve to work properly. Like char have a size of 1 byte, int equal 4 byte and float 32 byte. It's important to use the same data type to not have unpredictable result.
char a = 'a';
printf("%c",a);
int b = 50000;
printf("%d",b);
float c = 5.7;
printf("%f", c);
For more information: C-Variables

printf output for cross format specifier

The below program is printing 123828749, 0.000000 but I expected 123828749, 123828749.0. From where it is getting 0.000000 ?
#include <stdio.h>
void main()
{
double x = 123828749.66;
int y = x;
printf("%d\n", y);
printf("%lf\n", y);
}
Thanks
In the second call to printf you are passing an int, but the format string is %lf which expects a floating point value to be passed. This invokes undefined behaviour.
If you want to treat y as a floating point value when you pass it to printf, you'll need an explicit conversion:
printf("%lf\n", (double)y);
To answer more precisely to your question (even though David's answer is completely precise), when (at runtime) the format string gets parsed by printf function it expects double format. However, you supplied an int and since int is most likely not the same size as double (there is no indication that this is the case, though) your program read some junk memory and printed this unexpected result. This is where the zeroes came from.

Resources