Allegro.cc - Online Community

Allegro.cc Forums » Programming Questions » Network to / from host conversion

Credits go to BAF, CGamesPlay, gillius, HoHo, ImLeftFooted, Matt Smith, orz, and piccolo for helping out!
This thread is locked; no one can reply to it. rss feed Print
 1   2 
Network to / from host conversion
GullRaDriel
Member #3,861
September 2003
avatar

Hell ho !

I want to be able to send some double values over a network, but as I want to do it the right way I am in search of some converting function.

Have you ever hear about something as ntohd, htond functions ?

"Code is like shit - it only smells if it is not yours"
Allegro Wiki, full of examples and articles !!

CGamesPlay
Member #2,559
July 2002
avatar

No such function. Doubles are stored in IEEE-754 format on Intel, the same may be true for Macs. This being the case, you can simply transfer them as data.

--
Tomasu: Every time you read this: hugging!

Ryan Patterson - <http://cgamesplay.com/>

Matt Smith
Member #783
November 2000

As discussed before, it can often be more efficient to send numbers as text. It can even be more accurate if the numbers are rational e.g. 0.1

CGamesPlay
Member #2,559
July 2002
avatar

Not that the gained accuracy means anything, since you'll just convert it to base 2 when you receive it.

--
Tomasu: Every time you read this: hugging!

Ryan Patterson - <http://cgamesplay.com/>

piccolo
Member #3,163
January 2003
avatar

extern int StringToNumber(string MyString)
{
  istringstream converter(MyString);
  int result;
  converter >> result;
  return result;
}
extern string NumberToString(int Number)
{
  ostringstream converter;
  converter << Number;
  return converter.str();
}

wow
-------------------------------
i am who you are not am i

CGamesPlay
Member #2,559
July 2002
avatar

Great, and it has nothing to do with doubles ::)

--
Tomasu: Every time you read this: hugging!

Ryan Patterson - <http://cgamesplay.com/>

BAF
Member #2,981
December 2002
avatar

Just use that templated one posted a while back.

Matt Smith
Member #783
November 2000

It's true, but at least you can be sure the other side can convert it to its own format, using strtod() and sprintf()

GullRaDriel
Member #3,861
September 2003
avatar

Thanks to All, thanks to piccolo too ( even if you were not seeing what the question was ).

CGamesPlay: I was thinking so but waiting for someone to confirm.
Matt Smith: I got big and tons of values. Using sprintf trick is too much cost.

What I got tested: same byte order in all Intel/Amd. seem reversed for Sun/Aix.

A good job has been made there

I am waiting for BAF and his link !

I want to give cookies !

Quick !

:D

"Code is like shit - it only smells if it is not yours"
Allegro Wiki, full of examples and articles !!

HoHo
Member #4,534
April 2004
avatar

You could also use Allegro fixed point datatype. It should have guaranteed percision on all platforms. Only problem is limited range and percsision.

__________
In theory, there is no difference between theory and practice. But, in practice, there is - Jan L.A. van de Snepscheut
MMORPG's...Many Men Online Role Playing Girls - Radagar
"Is Java REALLY slower? Does STL really bloat your exes? Find out with your friendly host, HoHo, and his benchmarking machine!" - Jakub Wasilewski

gillius
Member #119
April 2000

Basically all machines use IEEE-754 floating point format. However, the endianess of this value is like any other issue. What I did for my network library GNE is to say that all values will be sent little-endian (I chose this because I expect virtually all peers to be little-endian). For floating point I said that I will send in little-endian IEEE-754 single or double precision. Well, Intel and Sun and PPC machines all use IEEE-754, so what the plan is just to say machines that don't support IEEE-754 are just simply "not supported" by any current port of GNE, and if I really need to do it, it isn't too onerous to actually parse a IEEE-754 number by breaking it into its components then using portable C to "convert" it to a float/double. But since I can't find a computer you actually need to do this for nor expect any target user of my library to have one, I never wrote the code.

So, in other words, do whatever you want as long as you precisely define it and give yourself a way out. If that's true, then if the unexpected happens, you can actually perform the work.

Gillius
Gillius's Programming -- https://gillius.org/

BAF
Member #2,981
December 2002
avatar

I don't recall what thread it was in, but it was something like (untested code I just wrote):

template<typename t> t ReadNum(std::string src)
{
    t ret;
    std::stringstream s(src);
    s >> ret;
    return ret;
}

template<typename t> std::string WriteNum(t src)
{
    std::stringstream ret;
    s << src;
    return s.str();
}

You would do something like:

string myString = WriteNum(myFloat);
// then:
float myFloat = ReadNum<float>(myString);

Again, untested, but probably works.

orz
Member #565
August 2000

What gillius said. Something like:

COMPILE_TIME_ASSERT(sizeof(float) == sizeof(int));
float ntohf ( float net_format ) {
   int r = ntohl((int&)net_format);
   return (float&)r;
}
float htonf ( float net_format ) {
   int r = htonl((int&)net_format);
   return (float&)r;
}

That requires that ints be 32 bit types. There's no pretty (by pretty I mean, without ifdefs) way to do the same for doubles, because doubles are 64 bit and there's no standard endianness conversion function for 64 bit values.

I do not like the use of text for this purpose. The advantages are that it is a variable length format that the standard library already supports. The disadvantages are that it has a space efficiency < 50% and its decimal nature makes it use more cycles than is needed for something as simple as encoding a floating point value.
If you were going to use text-based packets anyway though, why make your packets be stringstreams instead of using ReadNum/WriteNum wrappers?
edit:added missing paren

ImLeftFooted
Member #3,935
October 2003
avatar

Baf said:

untested, but probably works.

Heres a more optimized version:

template<typename t> t ReadNum(std::string src)
{
    t ret;
    std::istringstream s(src);
    s >> ret;
    return ret;
}

template<typename t> std::string WriteNum(t src)
{
    std::ostringstream ret;
    s << src;
    return s.str();
}

Probably good to overload a reference parm for ReadNum for cases where you need even less overhead.

template<typename t> void ReadNum(std::string src, t &ret)
{
    std::istringstream s(src);
    s >> ret;
}

CGamesPlay
Member #2,559
July 2002
avatar

That's not "more optimized", it's just a smaller vtable :P A more worthwhile optimization:

template<typename t> t ReadNum(const std::string& src)
{
    t ret;
    std::istringstream s(src);
    s >> ret;
    return ret;
}

template<typename t> std::string WriteNum(const t& src)
{
    std::ostringstream ret;
    s << src;
    return s.str();
}

--
Tomasu: Every time you read this: hugging!

Ryan Patterson - <http://cgamesplay.com/>

ImLeftFooted
Member #3,935
October 2003
avatar

Quote:

That's not "more optimized", it's just a smaller vtable

If it wasn't more optimized why would it exist?

GullRaDriel
Member #3,861
September 2003
avatar

Well, I got my problem resolved:

On all Intel (PC) computers, nothing to do.

I test the following:

1#include <stdio.h>
2 
3int main(){
4 
5FILE *out;
6 
7double toto = 3.1415926535;
8 
9out = fopen( "test" , "w" );
10 
11fwrite( &toto, sizeof( double ) , 1 , out );
12 
13fclose( out );
14 
15printf("%d\n",sizeof( double) );
16 
17}

On both the output value is 8 meaning that the size is the same.

On Intel bytes are ordered as following:

od -cx said:

od -cx test
0000000 D 027 A T 373 ! \t @
1744 5441 21fb 4009
0000010

On SUN this is the following:

od -cx said:

0000000 @ \t ! 373 T A 027 D
4009 21fb 5441 1744
0000010

So basically we can see that we should swap bytes by pack of two from start to end.

So basically we can see that we should swap bytes from start to end.

;D

Thanks to all !

Cookies time !

EDIT: WTF ! I did as you said in my test code (getting the double value when opening an intel file on a sun ) And I really dunno why I write a so silly mistake. Thanks for pointing it out, orz.

"Code is like shit - it only smells if it is not yours"
Allegro Wiki, full of examples and articles !!

orz
Member #565
August 2000

Quote:

So basically we can see that we should swap bytes by pack of two from start to end.

Nope. You should reverse in units of individual bytes, not sets of 2 bytes. The reason why you're seeing it in sets of 2 bytes is because you're printing them as 2-byte values, and the different endianness then hides the sub-2-byte ordering stuff. When changing endianness on any modern computer, the correct method is to reverse order in 1 byte units.

GullRaDriel
Member #3,861
September 2003
avatar

Fixed !

"Code is like shit - it only smells if it is not yours"
Allegro Wiki, full of examples and articles !!

CGamesPlay
Member #2,559
July 2002
avatar

Quote:

If it wasn't more optimized why would it exist?

If feet aren't meters why do they exist?

--
Tomasu: Every time you read this: hugging!

Ryan Patterson - <http://cgamesplay.com/>

ImLeftFooted
Member #3,935
October 2003
avatar

Quote:

If feet aren't meters why do they exist?

Because the geniuses who designed C++ didn't create the foot or the meter.

CGamesPlay
Member #2,559
July 2002
avatar

Do you actually know the details of how stringstream, istreamstream, and ostringstream work? What about stringbuf?

stringstream, istringstream, and ostringstream all use stringbuf internally. It's the same class.

--
Tomasu: Every time you read this: hugging!

Ryan Patterson - <http://cgamesplay.com/>

ImLeftFooted
Member #3,935
October 2003
avatar

Quote:

Do you actually know the details of how stringstream, istreamstream, and ostringstream work? What about stringbuf?

Yes sir.

CGamesPlay
Member #2,559
July 2002
avatar

Please either rephrase your original statement, support it, retract it or just stop posting.

--
Tomasu: Every time you read this: hugging!

Ryan Patterson - <http://cgamesplay.com/>

ImLeftFooted
Member #3,935
October 2003
avatar

You've given me so many options...

Anyway, my point that supported it fairly solidly was that the designers of C++ (lets make an acronym form them, how about Good Old [C++] DesierS) put a whole lot of thought into every bit of C++.

If the GODS thought that there should be an istringstream and an ostringstream class as opposed to just a single stringstream class then the GODS must of had a good reason. I don't question the GODS' purpose in this and yet I accept that the GODS are all knowing (in the domain of C++) and therefore I embrace and accept the istringstream into my life.

 1   2 


Go to: