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

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

  1. Angus

    Angus Guest

    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
    #1
    1. Advertising

  2. 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
    #2
    1. Advertising

  3. Angus

    jacob navia Guest

    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
    #3
  4. 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
    #4
  5. 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
    #5
  6. Angus

    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
    #6
  7. 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
    #7
  8. Angus

    Angus Guest

    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
    #8
  9. Angus

    Angus Guest

    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
    #9
  10. 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
    #10
  11. 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
    #11
  12. 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
    #12
  13. 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 Dijk, Apr 24, 2008
    #13
  14. Angus

    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
    #14
  15. Harald van Dijk <> 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
    #15
  16. 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
    #16
  17. Angus

    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
    #17
  18. 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
    #18
  19. 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 Dijk, May 5, 2008
    #19
  20. "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
    #20
    1. Advertising

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.
Similar Threads
  1. John Tsiombikas (Nuclear / the Lab)

    Re: Different results if compared as double or __int64?

    John Tsiombikas (Nuclear / the Lab), Jun 30, 2003, in forum: C++
    Replies:
    1
    Views:
    432
    Victor Bazarov
    Jun 30, 2003
  2. Vivi
    Replies:
    2
    Views:
    6,025
    ES Kim
    Aug 25, 2003
  3. Tim Clacy

    __int64 vs. long long

    Tim Clacy, Nov 10, 2003, in forum: C++
    Replies:
    8
    Views:
    844
    Rolf Magnus
    Nov 10, 2003
  4. JR
    Replies:
    3
    Views:
    386
    Xenos
    Feb 5, 2004
  5. Matt Whelan

    SWIG and __int64

    Matt Whelan, Aug 14, 2003, in forum: Python
    Replies:
    2
    Views:
    562
    Matt Whelan
    Aug 15, 2003
Loading...

Share This Page