# casting question - i64 = *((__int64*)&d);

Discussion in 'C Programming' started by Angus, Apr 23, 2008.

1. ### AngusGuest

I need to convert a double to a 64 bit integer. I am using __int64
but could of course use a more portable type.

To perform the correct casts:
double d = 3.3;
__int64 i64;
i64 = *((__int64*)&d);

//And to convert back
d = *((double*)&i64);

But I don't understand how this works. Can someone please explain?

Angus, Apr 23, 2008

2. ### Ben BacarisseGuest

Angus <> writes:

> I need to convert a double to a 64 bit integer. I am using __int64
> but could of course use a more portable type.
>
> To perform the correct casts:
> double d = 3.3;
> __int64 i64;
> i64 = *((__int64*)&d);
>
> //And to convert back
> d = *((double*)&i64);
>
> But I don't understand how this works. Can someone please explain?

You convert a pointer to the double -- &d -- to an __int64 pointer
-- (__int64 *)&d -- and then dereference that pointer to get the
64-bit integer that this converted pointer points to --
*(__int64 *)&d.

The code is not guaranteed to work (it is undefined behaviour) not
least because the resulting integer might be a trap representation.
Such code is very common. Much more portable is:

assert(sizeof d == sizeof i64);
memcpy(&i64, &d, sizeof d);

In fact the above is 100% portable, provided that one does not use the
resulting integer (which is often enough).

--
Ben.

Ben Bacarisse, Apr 23, 2008

3. ### jacob naviaGuest

Angus wrote:
> I need to convert a double to a 64 bit integer. I am using __int64
> but could of course use a more portable type.
>
> To perform the correct casts:
> double d = 3.3;
> __int64 i64;
> i64 = *((__int64*)&d);
>
> //And to convert back
> d = *((double*)&i64);
>
> But I don't understand how this works. Can someone please explain?

This will not work at all. You are reinterpreting memory
as a 64 bit integer, but you do NOT have a 64 bit
integer there!

A double has 3 parts: sign, exponent, and mantissa.

You will get a 64 bit integer with a value completely different
than the value stored in the double.

--
jacob navia
jacob at jacob point remcomp point fr
logiciels/informatique
http://www.cs.virginia.edu/~lcc-win32

jacob navia, Apr 23, 2008
4. ### Keith ThompsonGuest

Ben Bacarisse <> writes:
> Angus <> writes:
>
>> I need to convert a double to a 64 bit integer. I am using __int64
>> but could of course use a more portable type.
>>
>> To perform the correct casts:
>> double d = 3.3;
>> __int64 i64;
>> i64 = *((__int64*)&d);
>>
>> //And to convert back
>> d = *((double*)&i64);
>>
>> But I don't understand how this works. Can someone please explain?

>
> You convert a pointer to the double -- &d -- to an __int64 pointer
> -- (__int64 *)&d -- and then dereference that pointer to get the
> 64-bit integer that this converted pointer points to --
> *(__int64 *)&d.
>
> The code is not guaranteed to work (it is undefined behaviour) not
> least because the resulting integer might be a trap representation.

And because double and __int64 might have different alignment
constraints. Integer trap representations are fairly rare in the real
world; alignment constraints are common. Two types with the same size
are likely to have the same alignment constraints, though that's
certainly not guaranteed.

Note that if something like this causes a problem only rarely, the
conclusion to draw isn't necessarily that you can probably get away
with it; rather it means that it's a bug that can be very difficult to
detect.

> Such code is very common. Much more portable is:
>
> assert(sizeof d == sizeof i64);
> memcpy(&i64, &d, sizeof d);
>
> In fact the above is 100% portable, provided that one does not use the
> resulting integer (which is often enough).

Um, if you're not going to use the resulting integer, then what's the
point?

--
Keith Thompson (The_Other_Keith) <>
Nokia
"We must do something. This is something. Therefore, we must do this."
-- Antony Jay and Jonathan Lynn, "Yes Minister"

Keith Thompson, Apr 23, 2008
5. ### Richard TobinGuest

In article <funmbm\$8r5\$>, jacob navia <> wrote:

>> double d = 3.3;
>> __int64 i64;
>> i64 = *((__int64*)&d);
>>
>> //And to convert back
>> d = *((double*)&i64);

>This will not work at all. You are reinterpreting memory
>as a 64 bit integer, but you do NOT have a 64 bit
>integer there!
>
>A double has 3 parts: sign, exponent, and mantissa.
>
>You will get a 64 bit integer with a value completely different
>than the value stored in the double.

True, but that might be what he wants. If the idea is to get a 64-bit
integer with the same value as the double, it's certainly wrong. But
if he wants to inspect the bits of the double, then it's a plausible
way to do it.

Does this fall afoul of the type-based aliasing rules in C99?

-- Richard
--
:wq

Richard Tobin, Apr 23, 2008
6. ### Guest

On Apr 23, 10:04 am, Angus <> wrote:
> I need to convert a double to a 64 bit integer. I am using __int64
> but could of course use a more portable type.
>
> To perform the correct casts:
> double d = 3.3;
> __int64 i64;
> i64 = *((__int64*)&d);
>
> //And to convert back
> d = *((double*)&i64);
>
> But I don't understand how this works. Can someone please explain?

This code is broken and will or will not work depending on the
compiler and its settings, e.g. it won't work with gcc -O2. Use a
union to do that:

union {
double d;
__int64 i;
} u;
u.d = 3.3;
// use u.i now
// take u.d to "convert" u.i back to double

(If you are only going to compile your code with casts with
MS compiler, then it's probably fine as it is, it's unlikely
MS will break such code. But the code is broken nevertheless)

Yevgen

, Apr 23, 2008
7. ### Keith ThompsonGuest

jacob navia <> writes:
> Angus wrote:
>> I need to convert a double to a 64 bit integer. I am using __int64
>> but could of course use a more portable type.
>>
>> To perform the correct casts:
>> double d = 3.3;
>> __int64 i64;
>> i64 = *((__int64*)&d);
>>
>> //And to convert back
>> d = *((double*)&i64);
>>
>> But I don't understand how this works. Can someone please explain?

>
> This will not work at all. You are reinterpreting memory
> as a 64 bit integer, but you do NOT have a 64 bit
> integer there!
>
> A double has 3 parts: sign, exponent, and mantissa.
>
> You will get a 64 bit integer with a value completely different
> than the value stored in the double.

Which *might* be exactly what he wants. In my earlier followup, I
assumed that Angus actually wanted to obtain the representation of the
double value as a 64-bit integer. jacob is correct that this might
not make much sense; on the other hand, Angus hasn't given us enough
information to be sure about what he's trying to accomplish.

If you want to obtain the representation, using memcpy() as Ben
Bacarisse suggested is probably the best approach, though it can be
perilous.

If you want a *value* conversion, just assign it (the result will be
3, and you'll lose the .3 fractional part). (A cast will perform an
explicit value conversion, but it's usually not needed; in most
contexts, any needed conversion will be done implicitly.)

For example:

#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
int main(void)
{
double d = 3.3;
unsigned long long rep;
unsigned long long val;
assert(sizeof d == sizeof rep);
memcpy(&rep, &d, sizeof d);
val = d;
printf("d = %g\n", d);
printf("rep = 0x%llx\n", rep);
printf("val = %lld\n", val);
return 0;
}

On my system, I get:

d = 3.3
rep = 0x400a666666666666
val = 3

--
Keith Thompson (The_Other_Keith) <>
Nokia
"We must do something. This is something. Therefore, we must do this."
-- Antony Jay and Jonathan Lynn, "Yes Minister"

Keith Thompson, Apr 23, 2008
8. ### AngusGuest

On Apr 23, 5:29 pm, Keith Thompson <> wrote:
> jacob navia <> writes:
> > Angus wrote:
> >> I need to convert a double to a 64 bit integer.  I am using __int64
> >> but could of course use a more portable type.

>
> >> To perform the correct casts:
> >>     double d = 3.3;
> >>     __int64 i64;
> >>     i64 = *((__int64*)&d);

>
> >>     //And to convert back
> >>     d = *((double*)&i64);

>
> >> But I don't understand how this works.  Can someone please explain?

>
> > This will not work at all. You are reinterpreting memory
> > as a 64 bit integer, but you do NOT have a 64 bit
> > integer there!

>
> > A double has 3 parts: sign, exponent, and mantissa.

>
> > You will get a 64 bit integer with a value completely different
> > than the value stored in the double.

>
> Which *might* be exactly what he wants.  In my earlier followup, I
> assumed that Angus actually wanted to obtain the representation of the
> double value as a 64-bit integer.  jacob is correct that this might
> not make much sense; on the other hand, Angus hasn't given us enough
> information to be sure about what he's trying to accomplish.
>
> If you want to obtain the representation, using memcpy() as Ben
> Bacarisse suggested is probably the best approach, though it can be
> perilous.
>
> If you want a *value* conversion, just assign it (the result will be
> 3, and you'll lose the .3 fractional part).  (A cast will perform an
> explicit value conversion, but it's usually not needed; in most
> contexts, any needed conversion will be done implicitly.)
>
> For example:
>
> #include <stdio.h>
> #include <stdlib.h>
> #include <assert.h>
> int main(void)
> {
>     double d = 3.3;
>     unsigned long long rep;
>     unsigned long long val;
>     assert(sizeof d == sizeof rep);
>     memcpy(&rep, &d, sizeof d);
>     val = d;
>     printf("d = %g\n", d);
>     printf("rep = 0x%llx\n", rep);
>     printf("val = %lld\n", val);
>     return 0;
>
> }
>
> On my system, I get:
>
> d = 3.3
> rep = 0x400a666666666666
> val = 3
>
> --
> Keith Thompson (The_Other_Keith) <>
> Nokia
> "We must do something.  This is something.  Therefore, we must do this.."
>     -- Antony Jay and Jonathan Lynn, "Yes Minister"- Hide quoted text -
>
> - Show quoted text -

The reason for doing this is to transfer a double value across a
network using sockets. As I cannot think of a way to transport a
double value but I can send a 64 bit integer as a sequence of bytes
then this would work. Maybe I should be doing this totally some other
way.

As present I use an MS compiler for both ends of the connection so
that is not a problem. But maybe in the future that could change.

I was concerned that the memcpy way to do this might works but not if
I try to use the resulting integer! Well, that is not so useful...
Why can I not access the resulting integer?

Should I be doing this some other way?

Angus, Apr 23, 2008
9. ### AngusGuest

On Apr 23, 5:37 pm, Angus <> wrote:
> On Apr 23, 5:29 pm, Keith Thompson <> wrote:
>
>
>
>
>
> > jacob navia <> writes:
> > > Angus wrote:
> > >> I need to convert a double to a 64 bit integer.  I am using __int64
> > >> but could of course use a more portable type.

>
> > >> To perform the correct casts:
> > >>     double d = 3.3;
> > >>     __int64 i64;
> > >>     i64 = *((__int64*)&d);

>
> > >>     //And to convert back
> > >>     d = *((double*)&i64);

>
> > >> But I don't understand how this works.  Can someone please explain?

>
> > > This will not work at all. You are reinterpreting memory
> > > as a 64 bit integer, but you do NOT have a 64 bit
> > > integer there!

>
> > > A double has 3 parts: sign, exponent, and mantissa.

>
> > > You will get a 64 bit integer with a value completely different
> > > than the value stored in the double.

>
> > Which *might* be exactly what he wants.  In my earlier followup, I
> > assumed that Angus actually wanted to obtain the representation of the
> > double value as a 64-bit integer.  jacob is correct that this might
> > not make much sense; on the other hand, Angus hasn't given us enough
> > information to be sure about what he's trying to accomplish.

>
> > If you want to obtain the representation, using memcpy() as Ben
> > Bacarisse suggested is probably the best approach, though it can be
> > perilous.

>
> > If you want a *value* conversion, just assign it (the result will be
> > 3, and you'll lose the .3 fractional part).  (A cast will perform an
> > explicit value conversion, but it's usually not needed; in most
> > contexts, any needed conversion will be done implicitly.)

>
> > For example:

>
> > #include <stdio.h>
> > #include <stdlib.h>
> > #include <assert.h>
> > int main(void)
> > {
> >     double d = 3.3;
> >     unsigned long long rep;
> >     unsigned long long val;
> >     assert(sizeof d == sizeof rep);
> >     memcpy(&rep, &d, sizeof d);
> >     val = d;
> >     printf("d = %g\n", d);
> >     printf("rep = 0x%llx\n", rep);
> >     printf("val = %lld\n", val);
> >     return 0;

>
> > }

>
> > On my system, I get:

>
> > d = 3.3
> > rep = 0x400a666666666666
> > val = 3

>
> > --
> > Keith Thompson (The_Other_Keith) <>
> > Nokia
> > "We must do something.  This is something.  Therefore, we must do this."
> >     -- Antony Jay and Jonathan Lynn, "Yes Minister"- Hide quoted text -

>
> > - Show quoted text -

>
> The reason for doing this is to transfer a double value across a
> network using sockets.  As I cannot think of a way to transport a
> double value but I can send a 64 bit integer as a sequence of bytes
> then this would work.  Maybe I should be doing this totally some other
> way.
>
> As present I use an MS compiler for both ends of the connection so
> that is not a problem.  But maybe in the future that could change.
>
> I was concerned that the memcpy way to do this might works but not if
> I try to use the resulting integer!  Well, that is not so useful...
> Why can I not access the resulting integer?
>
> Should I be doing this some other way?- Hide quoted text -
>
> - Show quoted text -

Just thought I should also add that I definitely need the fractional
floating part.

Angus, Apr 23, 2008
10. ### Ben BacarisseGuest

Keith Thompson <> writes:
<snip>
> Ben Bacarisse <> writes:
>> Such code is very common. Much more portable is:
>>
>> assert(sizeof d == sizeof i64);
>> memcpy(&i64, &d, sizeof d);
>>
>> In fact the above is 100% portable, provided that one does not use the
>> resulting integer (which is often enough).

>
> Um, if you're not going to use the resulting integer, then what's the
> point?

Given a hash table that stores 6-bit ints keyed by, say, strings the
hack above could be used to press-gang that code into storing doubles.
This will remain portable (though ugly) if the hash table returns a
pointer to its value (often done, of course, because that gives
natural return value for "key not present"). It is not uncommon to
see hackery like this when one data structure is abused to store
values of some other type, and the results can be portable if the
values are never referenced until they are converted back.

If you meant the actual code above is useless, I agree, but it was an
illustration of an idea, not a working example.

--
Ben.

Ben Bacarisse, Apr 23, 2008
11. ### Ben BacarisseGuest

Angus <> writes:

> On Apr 23, 5:29Â pm, Keith Thompson <> wrote:

<snip>
>> If you want to obtain the representation, using memcpy() as Ben
>> Bacarisse suggested is probably the best approach, though it can be
>> perilous.

<snip>
>> --
>> Keith Thompson (The_Other_Keith) <>

Best not to quote signature blocks (the -- bit).

<snip>
> The reason for doing this is to transfer a double value across a
> network using sockets.

Ah. Much better just to send the bytes. C guarantees that all
objects can be accessed as unsigned char arrays. The payload of your
data packets is, usually, a sequence of unsigned chars, so just use:

memcpy(pkt_ptr, &d, sizeof d);

> As present I use an MS compiler for both ends of the connection so
> that is not a problem. But maybe in the future that could change.

If you need a method that works between different systems, the most
portable would be to convert the double to printable decimal, though
this can have consequences for converting back (you won't always get
the same double you started with).

> I was concerned that the memcpy way to do this might works but not if
> I try to use the resulting integer! Well, that is not so useful...
> Why can I not access the resulting integer?

Because it might be a trap representation. This won't be a problem on
today's boring architectures. Keith Thompson's other concern, that
the data might not be correctly aligned, won't be an issue if the
destination is a declared 64-bit int (say a variable or a field in a
struct). It *will* be a concern if you pull an 64-bit int out of an
arbitrary location in a message buffer:

long long int i =
*(long long int *)pkt_ptr; /* Eek! Anything could happen. */

--
Ben.

Ben Bacarisse, Apr 23, 2008
12. ### Keith ThompsonGuest

Ben Bacarisse <> writes:
> Angus <> writes:

[...]
>> I was concerned that the memcpy way to do this might works but not if
>> I try to use the resulting integer! Well, that is not so useful...
>> Why can I not access the resulting integer?

>
> Because it might be a trap representation. This won't be a problem on
> today's boring architectures. Keith Thompson's other concern, that
> the data might not be correctly aligned, won't be an issue if the
> destination is a declared 64-bit int (say a variable or a field in a
> struct). It *will* be a concern if you pull an 64-bit int out of an
> arbitrary location in a message buffer:
>
> long long int i =
> *(long long int *)pkt_ptr; /* Eek! Anything could happen. */

The original code was:

double d = 3.3;
__int64 i64;
i64 = *((__int64*)&d);

&d is appropriately aligned for type double. If __int64 requires
stricter alignment than double does, this could cause undefined
behavior. I wouldn't be surprised if this particular problem never
actually occurs, but the standard doesn't guarantee that it will work.

Using a union solves the alignment problem, but still invokes UB
because the standard specifically says so.

For transmitting the information across a network, the best solution
is probably just to treat the double value as an array of the
sizeof(double) unsigned chars, and copy it to a double object on the
receiving end. This assumes both ends use the same representation for
double.

If you can't make that assumption, you can transmit a textual
representation of the value, with enough digits to avoid losing
information.

--
Keith Thompson (The_Other_Keith) <>
Nokia
"We must do something. This is something. Therefore, we must do this."
-- Antony Jay and Jonathan Lynn, "Yes Minister"

Keith Thompson, Apr 23, 2008
13. ### Harald van DÄ³kGuest

On Wed, 23 Apr 2008 15:03:50 -0700, Keith Thompson wrote:
> The original code was:
>
> double d = 3.3;
> __int64 i64;
> i64 = *((__int64*)&d);
>
> &d is appropriately aligned for type double. If __int64 requires
> stricter alignment than double does, this could cause undefined
> behavior. I wouldn't be surprised if this particular problem never
> actually occurs, but the standard doesn't guarantee that it will work.
>
> Using a union solves the alignment problem, but still invokes UB because
> the standard specifically says so.

Nope, it doesn't. In C90, IIRC, reading a value from a union other than
the one last stored causes implementation-defined behaviour, but C99
requires the intended behaviour, which is a reinterpretation of the bit
pattern.

Harald van DÄ³k, Apr 24, 2008
14. ### Guest

On Apr 23, 5:03 pm, Keith Thompson <> wrote:
> Ben Bacarisse <> writes:
> > Angus <> writes:

> [...]
> >> I was concerned that the memcpy way to do this might works but not if
> >> I try to use the resulting integer! Well, that is not so useful...
> >> Why can I not access the resulting integer?

>
> > Because it might be a trap representation. This won't be a problem on
> > today's boring architectures. Keith Thompson's other concern, that
> > the data might not be correctly aligned, won't be an issue if the
> > destination is a declared 64-bit int (say a variable or a field in a
> > struct). It *will* be a concern if you pull an 64-bit int out of an
> > arbitrary location in a message buffer:

>
> > long long int i =
> > *(long long int *)pkt_ptr; /* Eek! Anything could happen. */

>
> The original code was:
>
> double d = 3.3;
> __int64 i64;
> i64 = *((__int64*)&d);
>
> &d is appropriately aligned for type double. If __int64 requires
> stricter alignment than double does, this could cause undefined
> behavior. I wouldn't be surprised if this particular problem never
> actually occurs, but the standard doesn't guarantee that it will work.
>
> Using a union solves the alignment problem,

As well as the actual problem of getting wrong results
on existing boring systems.

> but still invokes UB
> because the standard specifically says so.

But works in practice and will likely continue to work.

Yevgen

, Apr 24, 2008
15. ### Keith ThompsonGuest

Harald van DÄ³k <> writes:
> On Wed, 23 Apr 2008 15:03:50 -0700, Keith Thompson wrote:
>> The original code was:
>>
>> double d = 3.3;
>> __int64 i64;
>> i64 = *((__int64*)&d);
>>
>> &d is appropriately aligned for type double. If __int64 requires
>> stricter alignment than double does, this could cause undefined
>> behavior. I wouldn't be surprised if this particular problem never
>> actually occurs, but the standard doesn't guarantee that it will work.
>>
>> Using a union solves the alignment problem, but still invokes UB because
>> the standard specifically says so.

>
> Nope, it doesn't. In C90, IIRC, reading a value from a union other than
> the one last stored causes implementation-defined behaviour, but C99
> requires the intended behaviour, which is a reinterpretation of the bit
> pattern.

You're right. A footnote in C99 6.5.2.3 says:

If the member used to access the contents of a union object is not
the same as the member last used to store a value in the object,
the appropriate part of the object representation of the value is
reinterpreted as an object representation in the new type as
described in 6.2.6 (a process sometimes called "type
punning"). This might be a trap representation.

Note that a trap representation is a possibility in this case (though
most implementations don't have trap representations for integral
types).

--
Keith Thompson (The_Other_Keith) <>
Nokia
"We must do something. This is something. Therefore, we must do this."
-- Antony Jay and Jonathan Lynn, "Yes Minister"

Keith Thompson, Apr 24, 2008
16. ### Nick KeighleyGuest

On 23 Apr, 23:03, Keith Thompson <> wrote:

<snip>

> The original code was:
>
>      double d = 3.3;
>      __int64 i64;
>      i64 = *((__int64*)&d);

the OP is doing this to send a double over a notwork

<snip>

> For transmitting the information across a network, the best solution
> is probably just to treat the double value as an array of the
> sizeof(double) unsigned chars, and copy it to a double object on the
> receiving end.  This assumes both ends use the same representation for
> double.
>
> If you can't make that assumption, you can transmit a textual
> representation of the value, with enough digits to avoid losing
> information.

eg. sprintf()
or ASN.1
or XDR

there are hex representations of floats as well

--
Nick Keighley

Quality: this activity has been delayed due to higher priority tasks.

Nick Keighley, Apr 24, 2008
17. ### Guest

On Apr 24, 1:04 am, Keith Thompson <> wrote:
> Harald van D©¦k <> writes:
>
>
>
> > On Wed, 23 Apr 2008 15:03:50 -0700, Keith Thompson wrote:
> >> The original code was:

>
> >> double d = 3.3;
> >> __int64 i64;
> >> i64 = *((__int64*)&d);

>
> >> &d is appropriately aligned for type double. If __int64 requires
> >> stricter alignment than double does, this could cause undefined
> >> behavior. I wouldn't be surprised if this particular problem never
> >> actually occurs, but the standard doesn't guarantee that it will work.

>
> >> Using a union solves the alignment problem, but still invokes UB because
> >> the standard specifically says so.

>
> > Nope, it doesn't. In C90, IIRC, reading a value from a union other than
> > the one last stored causes implementation-defined behaviour, but C99
> > requires the intended behaviour, which is a reinterpretation of the bit
> > pattern.

>
> You're right.

That is UB, because of aliasing rules (of course it will do
something harmful only on a death station). And non-active
union member access wasn't UB in C90.

> A footnote in C99 6.5.2.3 says:
>
> [snip]
>
> Note that a trap representation is a possibility in this case (though
> most implementations don't have trap representations for integral
> types).

Note that the size mismatch is a possibility too. If you
do that type punning stuff, then you are probably aware
of the type characteristics, no? Funny stuff: when will
given implementation-specific code invoke UB?

Yevgen

, Apr 25, 2008
18. ### David ThompsonGuest

On Wed, 23 Apr 2008 23:04:39 -0700, Keith Thompson <>
wrote:

> Harald van D?k <> writes:
> > On Wed, 23 Apr 2008 15:03:50 -0700, Keith Thompson wrote:

> >> Using a union solves the alignment problem, but still invokes UB because
> >> the standard specifically says so.

> >
> > Nope, it doesn't. In C90, IIRC, reading a value from a union other than
> > the one last stored causes implementation-defined behaviour, but C99
> > requires the intended behaviour, which is a reinterpretation of the bit
> > pattern.

>
> You're right. A footnote in C99 6.5.2.3 says: <snip>

Only after (alleged!) correction by TC3-2007. FWTW.

- formerly david.thompson1 || achar(64) || worldnet.att.net

David Thompson, May 5, 2008
19. ### Harald van DÄ³kGuest

On Mon, 05 May 2008 04:10:33 +0000, David Thompson wrote:
> On Wed, 23 Apr 2008 23:04:39 -0700, Keith Thompson <>
> wrote:
>> Harald van D?k <> writes:
>> > On Wed, 23 Apr 2008 15:03:50 -0700, Keith Thompson wrote:

>
>> >> Using a union solves the alignment problem, but still invokes UB
>> >> because the standard specifically says so.
>> >
>> > Nope, it doesn't. In C90, IIRC, reading a value from a union other
>> > than the one last stored causes implementation-defined behaviour, but
>> > C99 requires the intended behaviour, which is a reinterpretation of
>> > the bit pattern.

>>
>> You're right. A footnote in C99 6.5.2.3 says: <snip>

>
> Only after (alleged!) correction by TC3-2007. FWTW.

The footnote only makes explicit what the original C99 standard already
required. C99 requires this behaviour by making sure the aliasing rules do
not disallow it and removing the wording saying the result is
implementation-defined. Please note that TC3 has made no relevant changes
in the normative text about this.

Harald van DÄ³k, May 5, 2008
20. ### Stephen SprunkGuest

"Angus" <> wrote in message
news:...
> The reason for doing this is to transfer a double value across a
> network using sockets. As I cannot think of a way to transport a
> double value but I can send a 64 bit integer as a sequence of bytes
> then this would work. Maybe I should be doing this totally some other
> way.
>
> As present I use an MS compiler for both ends of the connection so
> that is not a problem. But maybe in the future that could change.

....
> Should I be doing this some other way?

If you already understand how to send a 64-bit int over your socket by
reading it as an array of bytes, then just do the exact same thing with a
64-bit double; there is no need to stuff the double into an int first.

If you are using similar systems on either end, everything will be fine. If
not, you've got all sorts of problems with endianness, floating point
representation, variable sizes, etc. that may/will appear. Odds are,
though, that many of those problems will appear with your code to transfer
ints as well when you port it to a new system.

The safest and most portable way to transfer data between systems is to
convert it to a textual representation -- but FP types may lose a tiny bit
of accuracy during the conversion process. Any attempt at moving binary
data requires a lot of attention to specifying the wire format and code to
convert to/from that wire format on each machine, which has its own problems
but is typically faster.

> I was concerned that the memcpy way to do this might works but not if
> I try to use the resulting integer! Well, that is not so useful...
> Why can I not access the resulting integer?

Your double may be a trap representation when interpreted as an int. Using
memcpy() or a union eliminates the far more common problem of incorrect
alignment, though.

S

--
Stephen Sprunk "God does not play dice." --Albert Einstein
CCIE #3723 "God is an inveterate gambler, and He throws the
K5SSS dice at every possible opportunity." --Stephen Hawking

Stephen Sprunk, May 7, 2008

## Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.