Print int as float in C

I am using the Visual Studio TC compiler for Little Endian. The following is a snippet of code:

void main() { float c = 1.0; int a = 0x3F800000; int *ptr = (int *)&c; printf("\n0x%X\n", *ptr); printf("\na = %f", a); printf("\nc = %f", c); return; } 

Output:

 0x3F800000 a = 0.000000 c = 1.000000 

The value of Float 1.0 is 0x3F800000 and is stored as 00 00 80 3F in memory for Little Endian. The same value is assigned int a. How does printf print 0.000000 in some time 1.000000 for float c? I saw that it prints all integer values ​​as 0.000000 when printing using% f in printf.

Also, since printf is a variable argument, how does it know if the passed value is passed in int or float register?

+6
source share
7 answers

My psychic abilities tell me that Adam Liss's comment is the correct answer: the float arguments are pushed to double , so the printf() function expects this to happen: it expects a 64-bit value on the stack, but receives 32 bits plus garbage data that turns out to be zero.

If you increase the accuracy of the display, the display should look something like a = 0.00000000001 .

It also means this should work:

 void main() { double c = 1.0; long long a = 0x3FF0000000000000; long long *ptr = (long long *)&c; printf("\n0x%llX\n", *ptr); printf("\na = %f", a); printf("\nc = %f", c); return; } 
+5
source

I compiled your code in gcc and the generated code:

 movl $0x3f800000, %eax movl %eax, -4(%ebp) movl $1065353216, -8(%ebp) leal -4(%ebp), %eax movl %eax, -12(%ebp) movl -12(%ebp), %eax movl (%eax), %eax movl %eax, 4(%esp) movl $LC1, (%esp) call _printf movl -8(%ebp), %eax movl %eax, 4(%esp) movl $LC2, (%esp) call _printf flds -4(%ebp) fstpl 4(%esp) movl $LC3, (%esp) call _printf 

This may give you a hint that the float parameters are not taken from the regular stack, but rather from the floating-point stack ... I would expect something random to happen, not 0 ...

+5
source

As -Wall says: warning: format '%f' expects type 'double', but argument 2 has type 'int' . This behavior is undefined, as described in more detail here .

If the conversion specification is not valid, the behavior is undefined. If any argument is not the correct type for the corresponding coversion specification, the behavior is undefined.

So what you see here is what the compiler decided, which could be anything.

+4
source

In any C implementation, there are rules about how parameters are passed to functions. These rules may indicate that parameters of certain types are passed in certain registers (for example, integer types in general registers and floating-point types in separate floating-point registers), that large arguments (for example, structures with many elements) are passed onto the stack or a pointer to a copy of the structure, etc.

Inside the function being called, the function looks for the parameter that it expects in those places that are specified in the rules. When you pass an integer in the printf argument, but pass it %f in the format string, you put the integer somewhere, but tell printf to look for a float (which has been increased to double). If you specify in the C implementation rules that the integer argument is passed in the same place as the double argument, then printf will find the bits of your integer, but will interpret them as double. On the other hand, if the rules for your C implementation specify different places for the arguments, then the bits of your integers are not where printf looking for a double. So printf finds some other bits that have nothing to do with your integer.

In addition, many C implementations have 32-bit int types and 64-bit double types. The %f specifier is intended to print double, not float, and the float value you passed is converted to double before calling the function. Thus, even if printf finds the bits of your integer, there are only 32 bits, but printf uses 64. Thus, the printed double consists of 32 bits that you transmitted and 32 other bits, and this is not the value you plan to print .

This is why the format specifiers you use must match the arguments you pass.

+2
source

I encounter a similar problem, and finally, I developed a way to solve it, not sure what you want. The key point is that you must pass a float instead of an integer.

 #include <stdio.h> void printIntAsFloat(); int main(void){ printIntAsFloat(); } void printIntAsFloat(){ float c = 1.0; int a = 0x3F800000; int *ptr = (int *)&c; float *fp = (float*)((void*)&a); /*this is the key point*/ printf("\n0x%X\n", *ptr); printf("\na = %f", a); printf("\nc = %f", c); printf("\nfp = %f", *fp); return; } 

The output is as follows:

 0x3F800000 a = 0.000000 c = 1.000000 fp = 1.000000 

OS: Fedora21 64 bit GCC version: gcc version 4.9.2 20141101 (Red Hat 4.9.2-1) (GCC)

0
source
 int a= 0x3F800000; printf("\na = %f", *(float*)&a);//1.0 
-1
source

enter variables

 printf("\na = %f", (float)a); printf("\nc = %f", (float)c); 
-2
source

Source: https://habr.com/ru/post/945261/


All Articles