How can we explain the following behavior of c++ code ?

Hi,

I am finding it difficult to understand the following c++ code behavior.

[1]
1
2
3
4
  double dz = 23.4;
  int* p = (int*)(&dz);
  *p = 432344332;
  std::cout << dz;



23.4




[2]
1
2
3
4
  double dz = 23.4;
  long* p = (long*)(&dz);
  *p = 432344332;
  std::cout << dz;



2.13606e-315



In the above code, why the value of dz changes in case [2] while it remains same in case [1] ?

Thanks for any help :)
The program violates the strict aliasing rule, and therefore its behavior is undefined.
Last edited on
why the value of dz changes in case [2] while it remains same in case [1] ?

Blind luck.

You define dz as a double. That means the bits within dz have specific meanings that, taken together, represent floating point numbers.

1
2
int* p = (int*)(&dz);
*p = 432344332;
says "pretend that dz contains an int, not a double. Now store 432344332 in the bytes at dz." In other words, it stores the bit pattern representing integer 432344332 into the location where dz is stored.

Since integers and doubles use very different bit patterns (and even different numbers of bits!), you've basically now stored garbage in dz.

The fact that the first example results in no change in value is a red herring. Someone figured out exactly what bit pattern encodes the double 23.4, figured out what the corresponding bits represent when interpreted as an integer, and used that in the code. After all, isn't 432344332 a strange number to store?

So why does the second example produce a different result? Because ints and longs use different bit encodings (specifically, they probably use different numbers of bytes).
So this is the reason typecasting is considered a bad practice in c++.
Thanks mbozzi and dhayden for your replies :)
Your case 1 does change.
But not by much.

Anything you do to the lower 32-bits of a double only come in beyond about the 6th significant digit.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
#include <iostream>
#include <iomanip>
using namespace std;

union f {
    double  d;
    long    l;
    int     i[2];
    unsigned char c[8];
    friend ostream &operator <<(ostream &os, const union f & f ) {
        os << "d=" << setprecision(16) << f.d << endl;
        os << "l=" << f.l << " " << showbase << hex << f.l << dec << endl;
        os << "i[0]=" << f.i[0] << ", i[1]=" << f.i[1] << "   " << showbase << hex << f.i[0] << "," << f.i[1] << dec << endl;
        for ( int c = 0 ; c < 7 ; c++ ) {
            os << showbase << hex << setfill('0') << setw(2) << (unsigned)f.c[c] << " ";
        }
        os << dec << endl;
        return os;
    }
};

int main ( ) {
    cout << sizeof(double) << endl;
    cout << sizeof(long) << endl;
    cout << sizeof(int) << endl;
    f foo;
    foo.d = 23.4;
    cout << foo << endl;
    foo.i[0] = 432344332;  // Like *p = 432344332; 
    cout << foo << endl;
}
Topic archived. No new replies allowed.