bugger
bugger

Reputation: 169

Printing int as float in C

I'm using Visual Studio TC compiler for Little Endian. The following is the piece 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;    
}

The output is:

0x3F800000
a = 0.000000
c = 1.000000

Float value 1.0 is 0x3F800000 and stored as 00 00 80 3F in memory for Little Endian. The same value is assigned to int a. How printf prints 0.000000 for int a while 1.000000 for float c? I've seen it prints all integer values as 0.000000, when printed using %f in printf.

Also, since printf is variable argument function, how does it knows whether the passed value in the register is int or float?

Upvotes: 7

Views: 11853

Answers (7)

Chris.Huang
Chris.Huang

Reputation: 555

I meet the similar issue , and finally I develop a way to solve it , not sure whether that's what you want.The key point is that : you should pass a float instead of a 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 like this :

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)

Upvotes: 1

Eric Postpischil
Eric Postpischil

Reputation: 223872

Within any C implementation, there are rules about how parameters are passed to functions. These rules may say that parameters of certain types are passed in certain registers (e.g., integer types in general registers and floating-point types in separate floating-point registers), that large arguments (such as structures with many elements) are passed on the stack or by a pointer to a copy of the structure, and so on.

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

Also, many C implementations have 32-bit int types and 64-bit double types. The %f specifier is for printing a double, not a float, and the float value you pass is converted to double before calling the function. So, even if printf finds the bits of your integer, there are only 32 bits there, but printf uses 64. So the double that is printed is made up of 32 bits you passed and 32 other bits, and it is not the value you intended to print.

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

Upvotes: 2

Medinoc
Medinoc

Reputation: 6608

My psychic powers tell me Adam Liss's comment is the right answer: float arguments are promoted to double, so the printf() function expects that to happen: It expects a 64-bit value on the stack, but gets 32 bits plus garbage data that happen to be zero.

If you increase the display precision, the display should be something like a = 0.00000000001.

This 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;    
}

Upvotes: 7

BLUEPIXY
BLUEPIXY

Reputation: 40155

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

Upvotes: -1

Bort
Bort

Reputation: 2491

As -Wall states: warning: format ‘%f’ expects type ‘double’, but argument 2 has type ‘int’. This is undefined behavior as also explained in more detail here.

If a conversion specification is invalid, 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 builder decided to happen, which can be anything.

Upvotes: 5

V-X
V-X

Reputation: 3029

I have compiled your code in gcc and the code generated is following:

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 could give you a hint, that float parameters are not taken from the regular stack but rather from the stack of floating points... I would expect that there would be something random rather than 0...

Upvotes: 5

mf_
mf_

Reputation: 625

cast the variables

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

Upvotes: -1

Related Questions