-2
#include <stdio.h>
void print_binary(int n);
void test();

int main(){
    test();
    return 0;
}
void print_binary (int n){
    unsigned int mask = 0;
    mask = ~mask^(~mask >> 1);
    for (; mask != 0; mask >>= 1){
        putchar ((n & mask) ? '1' : '0');
    }
}
void test(){
    int x;
    float *p;
    p = (float *) &x;
    printf ("x init value :%d\n", x);
    printf ("addr x and p are %p %p\n", &x, p);
    printf ("print x in bit ");
    print_binary(x);
    printf ("\n");//00000000000000000000000000000000
    *p = 6.35;
    printf ("print x in bit ");
    print_binary(x);
    printf ("\n");//01000000110010110011001100110011
    printf ("x after 6.35 value :%d\n", x);//1087058739
    printf ("call1 x:%.100f\n", x);//0.0000000.....
    printf ("x:%d\n", x);//1087058739
    printf ("call2 x:%f\n", x);//0.000000
    printf ("p:%f\n", *p);//6.350000
    printf ("call3 x:%f\n", x);//6.350000
}

Results:

x init value :0                                                                                                                                                                    
addr x and p are 0x7ffc37d5ba8c 0x7ffc37d5ba8c                                                                                                                                     
print x in bit 00000000000000000000000000000000                                                                                                                                    
print x in bit 01000000110010110011001100110011                                                                                                                                    
x after 6.35 value :1087058739                                                                                                                                                     
call1 x:0.0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000                                                                     
x:1087058739                                                                                                                                                                       
call2 x:0.000000                                                                                                                                                                   
p:6.350000                                                                                                                                                                         
call3 x:6.350000

I print my x after *p = 6.35;, and in the memory, we get 01000000110010110011001100110011, this is the right number according to the IEEE754, could someone explain why my first printf ("call1 x:%.100f\n", x) print me 0.00..., but after I printf ("p:%f\n", *p), it can print the 6.35 ?

M.aster
  • 1
  • 2
  • 1
    Maybe because you compiling with debug setting on that will set to 0 your memory ? You don't initialize "x", so it could be anything, not 0 in particulary. What are your compilation option ? – Tom's Aug 27 '18 at 09:36
  • I init my x with *p = 6.35; – M.aster Aug 27 '18 at 09:40
  • 1
    Yeah, AFTER some `printf`s – Fureeish Aug 27 '18 at 09:46
  • In your title you are mixing "returns" with "prints" as you do not check the return value in your code. – Gerhardh Aug 27 '18 at 09:59
  • 1
    Note that `*p = 6.35;` is *strict aliasing violation*, because you are using wrong type `float` to assign into the `int`. This results in *undefined behaviour*, which means means your program is broken, unless you have set your compiler to non-standard mode. – user694733 Aug 27 '18 at 10:16

2 Answers2

1

Dereferencing p is undefined behavior, since p is not pointing to a float, but to an int (ref. eg. What is the strict aliasing rule?).

Also, trying to print an int with the "%f" format specifier is undefined behavior, since that format specifier expects a double (ref. eg. Why does printf("%f",0); give undefined behavior?).

So, you can't rely on any behavior of this code - anything is possible.

In practice, what's probably happening, is that the compiler decided to move *p = 6.35; to right before printf ("p:%f\n", *p);.

Sander De Dycker
  • 16,053
  • 1
  • 35
  • 40
0

From your tags (type-conversion and implicit conversion) you seem to expect some type conversion to happen. This is not the case.

Accessing memory with ill-typed pointer does not trigger any conversion to happen. It simply interpretes the memory in a different way. This includes violating the strict aliasing rules causing undefined behaviour.

And when you use

printf ("call1 x:%.100f\n", x);//0.0000000.....

you are cheating your compiler. You promise to pass a double value (%f format specifier) which typically holds 8 bytes but then you only pass 4 bytes of an integer. Mismatch in type specifier and parameter type causes undefined bahaviour and all expectations are worhless.

Then again you use

printf ("p:%f\n", *p);//6.350000

which works fine as you provide the proper double parameter. (here is the only implicit type conversion)

Your compiler should print some warnings when you try to compile this code. And you should always listen to the compiler and resolve the warnings.

Gerhardh
  • 11,688
  • 4
  • 17
  • 39
  • But why in the last line, the printf ("call3 x:%f\n", x);//6.350000? – M.aster Aug 27 '18 at 10:28
  • Why not? It's undefined. If the right bits are in correct position it may print what you expect. Just by accident. – Gerhardh Aug 27 '18 at 10:29
  • But there are no difference between `printf ("call1 x:%.100f\n", x);` and `printf ("call3 x:%f\n", x);`. The printf is an variadic function, they should have the same output. – M.aster Aug 27 '18 at 10:46
  • You only pass 4 bytes where 8 bytes are needed. The other 4 bytes are unspecified. Random content of the stack cannot be expected to contain a certain value. – Gerhardh Aug 27 '18 at 10:48