Thread: linux, doubles, and unions

  1. #1
    Registered User
    Join Date
    Jul 2008
    Posts
    12

    linux, doubles, and unions

    Hi All,

    I have a pretty bizarre problem going on regarding Linux. Our software is running on Unix and now we are porting to Linux. The problem involves a 'double' type within a union. This double/union combo is not our software, we interface with it via them sending data over a socket. The struct looks something like this:

    s
    Code:
    ome struct{
    int type;
    union
    {
      char cval;
      long ival;
      double fval;
      struct
      {
        int len;
        char val[61];
      } sval;
    } v;
    } t_some_struct;
    going from solaris to solaris, there is no problem. going from (writing from) solaris to linux (reading off the socket on linux) doesnt seem to work properly.

    there is code that checks the type, then copies from the proper field in the struct to a proper type (double to double). We always get 0 in linux.

    I tried to break it down by printout out byte by byte (using "v", memcpy'd into a char[8] and printed each byte). The byte by byte printout produces the same result when reading off the socket on solaris and linux. when the "fval" is looked at on solaris after reading off the socket, it looks correct. when the "fval" is looked at on linux, it is zero.

    for instance

    Code:
    char    test[8];
    
    memcpy (&test, &something.v, 8)
    for (int i = 0; i < 8; i++0
    printf("[%d]: %x\n", i, test[i]);
    I get something like:
    [0]: 40
    [1]: 26
    [2]: 72
    [3]: 5a
    [4]: 25
    {5]: f
    [6]: ffffff84
    [7]:0

    the double value on solaris is (in this case 11.223344. Print out the double value on linux and you get 0. But the hex dumps are the same on linux and solaris.

    Is there some trick that I am missing????

    I appreciate any input.

    thanks,
    Bill

  2. #2
    Hail to the king, baby. Akkernight's Avatar
    Join Date
    Oct 2008
    Location
    Faroe Islands
    Posts
    717
    How come you are using struct's without names o.O?
    Currently research OpenGL

  3. #3
    Kernel hacker
    Join Date
    Jul 2007
    Location
    Farncombe, Surrey, England
    Posts
    15,677
    My guess is that you are hitting a byte-order issue - your low end byte is transferred at the other end of the double. Of course, I also suspect when you are talking about Linux and Solaris, that you are running Linux on a x86 machine, and Solaris on a sparc. If you are using Sparc Solaris and Sparc Linux or x86 Solaris and x86 Linux, then that's not the answer.

    --
    Mats
    Compilers can produce warnings - make the compiler programmers happy: Use them!
    Please don't PM me for help - and no, I don't do help over instant messengers.

  4. #4
    and the Hat of Guessing tabstop's Avatar
    Join Date
    Nov 2007
    Posts
    14,336
    Do you get zero exactly? If you print using %e, say, do you get, oh I don't know, 3.57065e-306?

  5. #5
    and the hat of int overfl Salem's Avatar
    Join Date
    Aug 2001
    Location
    The edge of the known universe
    Posts
    39,660
    matsp is right - http://en.wikipedia.org/wiki/Endianness
    The processors implied by your choice of OS have different endian.
    If you dance barefoot on the broken glass of undefined behaviour, you've got to expect the occasional cut.
    If at first you don't succeed, try writing your phone number on the exam paper.

  6. #6
    Registered User
    Join Date
    Jul 2008
    Posts
    12

    Thanks

    yes, when I print with %e or %d I get actual values (like the one you showed).

    If it is a problem with the big/little endian issue, why would my integers that come over the socket look ok? In this case, I also tried executing ntohd (htond) but the answer still came out zeroes. Any ideas?

  7. #7
    Kernel hacker
    Join Date
    Jul 2007
    Location
    Farncombe, Surrey, England
    Posts
    15,677
    htond or something similar SHOULD WORK. Note that you need to do this at both ends, as you should not really know which is right and which is wrong.

    --
    Mats
    Compilers can produce warnings - make the compiler programmers happy: Use them!
    Please don't PM me for help - and no, I don't do help over instant messengers.

  8. #8
    Registered User
    Join Date
    Jul 2008
    Posts
    12

    more

    I must be doing something really wrong. I wrote a test client/server program and tried many variations. I tried htonX on the server/sparc side and ntohX on the linux side. I tried removing the byte swapping on either side and removing them all together. Still, linux has trouble with doubles. This has to be a word align issue, wouldnt you think? And if so, how in the heck do you get around it? I would hope that somebody has encountered this same situation before and has some kind of solution????? -Bill

  9. #9
    and the hat of int overfl Salem's Avatar
    Join Date
    Aug 2001
    Location
    The edge of the known universe
    Posts
    39,660
    A simple test to run on both machines.
    Code:
    #include <stdio.h>
    int main ( ) {
        double magic = 1234.5678;
        unsigned char test[sizeof(magic)];
        memcpy( test, &magic, sizeof(magic) );
        for (int i = 0; i < sizeof(magic); i++ )
            printf("[&#37;d]: %02x\n", i, test[i]);
        return 0;
    }
    Do you get the same number of bytes, with the same values, in the same order on both machines?
    If you dance barefoot on the broken glass of undefined behaviour, you've got to expect the occasional cut.
    If at first you don't succeed, try writing your phone number on the exam paper.

  10. #10
    Registered User
    Join Date
    Nov 2008
    Posts
    75
    I'm sure you would have seen all your problems by yourself if, instead of doing this totally buggy test :
    Code:
    char    test[8];
    
    memcpy (&test, &something.v, 8)
    for (int i = 0; i < 8; i++0
    printf("[&#37;d]: %x\n", i, test[i]);
    You had done something correct like copying all the bytes of that union. Inside that union there's this :
    Code:
    struct
      {
        int len;
        char val[61];
      } sval;
    So why did you think that copying just 8 bytes would have been right?

  11. #11
    Kernel hacker
    Join Date
    Jul 2007
    Location
    Farncombe, Surrey, England
    Posts
    15,677
    But unless the compiler is not doing what all compilers I know of does when it comes to unions and the placement of data in them, the double should live in the first 8 bytes of the union. The fact that the union has other members that are longer doesn't change this.

    --
    Mats
    Compilers can produce warnings - make the compiler programmers happy: Use them!
    Please don't PM me for help - and no, I don't do help over instant messengers.

  12. #12
    Registered User
    Join Date
    Nov 2008
    Posts
    75
    Quote Originally Posted by matsp View Post
    But unless the compiler is not doing what all compilers I know of does when it comes to unions and the placement of data in them, the double should live in the first 8 bytes of the union. The fact that the union has other members that are longer doesn't change this.

    --
    Mats
    What I was saying is that by copying the whole union and looking at all the different "views"(the different forms given by the variables you choose to look at) of it, it would have given more insight about the problem. Or maybe not if he didn't know anything at all about byte order problems. In this case you could have seen it by looking at the first 8 bytes alone because it was just a byte order problem, but in a more complex situation(data corruption over the network), the partial copy may have been misleading.

  13. #13
    Registered User
    Join Date
    Jul 2008
    Posts
    12

    Bill

    Actually, I did print out all of the bytes in the union. Every byte past the 8th byte had zeros in it.

  14. #14
    Registered User
    Join Date
    Nov 2008
    Posts
    75
    Quote Originally Posted by paraglidersd View Post
    Actually, I did print out all of the bytes in the union. Every byte past the 8th byte had zeros in it.
    Yes, that was to be expected, but I thought you actually tested the union just with the code you showed here. But if you did that, then disregard my comment.

  15. #15
    Registered User
    Join Date
    Jul 2008
    Posts
    12

    Foot in mouth

    I owe all of you an apology (though I thank all of you because I learned some things from your posts). As such, I have my foot placed firmly in mouth (or tail, whichever you prefer).

    Turns out that 'htond' and 'ntodh' are not system routines. We had those routines coded up, and subsequently 'ifdef'd out (well, they had #ifdef WIN32). So, once I fixed the ifdef situation, my floats and doubles came out correctly because the byte swapping actually happened.

    Again, I thank all of you for responding and helping me.

    Bill

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Double's and floats, i need their bytes.
    By Florian in forum C++ Programming
    Replies: 26
    Last Post: 07-08-2008, 05:42 PM