4

I'm trying to create a double by appending the binary representations of two ints. This is what I have now:

int i = arc4random();
*(&i+1) = arc4random();
double d = *(double*)&i;

I hoped the double pointer would also use the value in the &i+1 address, and this is indeed the case. When I print the binary representations of i and *(&i+1) and compare them to the binary representation of d, d is composed by appending *(&i+1) and i. So *(&i+1) comes first?! Why is this the case?

EDIT: also take a look at the answers of Juan Catalan and Mark Segal to know what's the right way of doing what I did using unions.

Rugen Heidbuchel
  • 377
  • 2
  • 14
  • 5
    DO NOT DO THIS! You are invoking undefined behaviour by using memory not allocated for variables. – Sami Kuhmonen May 30 '15 at 19:11
  • [Binary operations on doubles in C](http://stackoverflow.com/q/20458125). Also keep in mind that with this scheme you could generate a `NaN`. – jscs May 30 '15 at 19:15
  • If you ever really need to generate a NaN, `strtod("NaN")`. `strtod("inf")` is useful, too. – luser droog May 30 '15 at 19:16
  • 3
    Use a `union` instead. You still could generate a `NaN` But won't have memory management issues. – Juan Catalan May 30 '15 at 19:17
  • @SamiKuhmonen Can I create a double variable, converts it's address to an int pointer and set the values like that? Then I allocated the memory for the double variable, no? I'm still curious to why the *(&i+1) value is in the first part. I tried it 20 times or so and it always worked... – Rugen Heidbuchel May 30 '15 at 19:19
  • @JuanCatalan That's a good idea, I didn't think of that! :) – Rugen Heidbuchel May 30 '15 at 19:20
  • 2
    This is the whole purpose of a `union`, share a memory block among several different types. Be careful though about `sizeof(int)` you have to make sure it is half the size of the `double` in your architecture. – Juan Catalan May 30 '15 at 19:23
  • @JuanCatalan I did check that, and that's the case. Thanks for your help. If you put your comments in an answer, I can check it. (and you can get the credit you deserve :) ) – Rugen Heidbuchel May 30 '15 at 19:26
  • 2
    double values are NOT two int values in a row. please read which discusses the actual format used for a double variable in C. – user3629249 May 30 '15 at 20:05

3 Answers3

4

Use a union instead. You still could generate a NaN But won't have memory management issues.

This is the whole purpose of a union, share a memory block among several different types.

Make sure in your architecture sizeof(double) is equal to twice sizeof(int)

Juan Catalan
  • 2,299
  • 1
  • 17
  • 23
2

You could either use a union, like this:

typedef union {
    double d;
    struct {
        int a;
        int b;
    } integers;
} double_generator;

int main(void) {
    double_generator g;
    g.integers.a = arc4random();
    g.integers.b = arc4random();

    // g.d is now a "randomly generated double"

    return 0;
}

Or "manually", possibly unsafely, do the job yourself:

int main(void) {
    double d;
    *((int *)&d) = arc4random();
    *(((int *)&d) + 1) = arc4random();
    printf("%f", d);
    return 0;
}

In both cases, you simply address the same memory as if it was int or double. This could generate every possible double value, including NaN or Infinity.

However, this code assumes that sizeof(double) is (at least) twice as sizeof(int). If it isn't, you must introduce different code to handle that.

Mark Segal
  • 5,427
  • 4
  • 31
  • 69
1

When I print the binary representations of i and *(&i+1) and compare them to the binary representation of d, d is composed by appending *(&i+1) and i. So *(&i+1) comes first?! Why is this the case?

the actual ordering of the bytes depends upon the 'Endian-ness' of the underlying hardware architecture.

with little Endian architecture:

1) the lowest address byte contains the least significant 8 bits of the total variable  
2) the highest address byte contains the most significant 8 bits of the total variable.
user3629249
  • 16,402
  • 1
  • 16
  • 17