5

I'd like to send some double precision floating point numbers over the network. (standard C, standard sockets) There is no htond or ntohd to convert the data to and from network byte order. What should I do? I have a couple solutions in my head but I'd like to know what the common practice is.

(I'd also like to know what is the common practice for sending 64bit ints, like gint64 values used by gstreamer)

edit: This is one solution I thought of. I presume it works for any size integers, but is it correct for doubles?

void swap_if_necessary (void* buff, int buff_len) 
{
    uint32_t foo = 1;
    if ( htonl(foo) != foo ) 
    {
        char* to_swap = (char*)buff;

        int i;
        for (i = 0; i < buff_len/2; i++)
        {
            char  swap_buff = to_swap[i];
            to_swap[i] = to_swap[buff_len -1 -i];  
            to_swap[buff_len -1 -i] = swap_buff;
        }  
    }
}
dec-vt100
  • 190
  • 2
  • 9
  • [This section on Wikipedia](http://en.wikipedia.org/wiki/Endianness#Floating-point_and_endianness) explains the situation well. – hammar May 21 '11 at 20:34
  • 1
    Wouldn't you just send the 64-bit integer big endian like all other integers? How would that be different than other integers? – Chris Lutz May 21 '11 at 21:11
  • the problem is should I convert it to big endian myself, or is there some library that does that for me. The standard bsd sockets only have functions for 32 and 16 bit integers. – dec-vt100 May 21 '11 at 21:16
  • 1
    GCC provides `__builtin_bswap64()` - see http://gcc.gnu.org/onlinedocs/gcc/Other-Builtins.html – Nikolai Fetissov May 21 '11 at 21:43

3 Answers3

10

Convert it to an agreed string format and send that. Not sure if it's common practice or even decent, but it worked for me (it is true I did not care about performance at that point since I wasn't sending very many values).

cnicutar
  • 178,505
  • 25
  • 365
  • 392
  • 2
    It is common practice actually. There are simply too many variations on floating point formats. Converting from or to IEEE would be as expensive as using `strtod`. If you want to send a lot of data and want cheap conversion (sound, positions in a real time 3D game,...), consider sending fixed point numbers. – Alexandre C. May 21 '11 at 21:59
  • I have used `sprintf(...,"%.*e", DBL_DECIMAL_DIG -1, x)` to be sufficient to uniquely convert `double`, (except NaN with a payload). `sprintf(...,"%a", x)` is good too. – chux - Reinstate Monica Mar 25 '15 at 17:29
5

What Andre is saying is that binary floating point numbers are not trustworthy across networks because of differences between different computer architectures. Differences that go beyond byte order (big/little endian). Thus things like converting to strings or use of libraries such as XDR, is really necessary if there is any chance your data is going to be processed by different computer architectures.

The simple formats of integers and characters can slip through with just endian adjustments but floating point gets more complex.

Gilbert
  • 3,740
  • 17
  • 19
  • 1
    I think I'll do my own byte swap, the one I added in my question edit, but on 64bit ints instead of doubles. To be honest 64bit ints are enough for me. I want to send some time-related information I retrieve from gstreamer. It stores time intervals as number of milliseconds in 64 bit integers. I was just converting them to double for my own "satisfaction" because I'm used to NSTimeinterval, a time interval stored as the number of seconds (double floating point), used throughout Apple(iOS and OSX) C and ObjectiveC frameworks. – dec-vt100 May 21 '11 at 22:02
4

You might want to look at XDR which was first defined in rfc1014. Obviously, you want to find a library which implements XDR for your platform.

Community
  • 1
  • 1
Andre Holzner
  • 18,333
  • 6
  • 54
  • 63