Jump to content

  • Log In with Google      Sign In   
  • Create Account


Sending float Windows <-> Linux


Old topic!
Guest, the last post of this topic is over 60 days old and at this point you may not reply in this topic. If you wish to continue this conversation start a new topic.

  • You cannot reply to this topic
11 replies to this topic

#1 polyfrag   Crossbones+   -  Reputation: 1822

Like
0Likes
Like

Posted 03 July 2012 - 10:22 AM

I send a float equal to 4.000 from Windows to an Amazon EC2 Linux server, but the server reads it as 8.47522e+11.
The server sends back 4.000 but Windows reads it as 0.0.
I tried changing the byte order using this on Windows:

void ReverseFloat(float* f)
{
  unsigned char* uc = (unsigned char*)f;
  unsigned char temp = uc[0];
  uc[0] = uc[3];
  uc[3] = temp;
  temp = uc[1];
  uc[1] = uc[2];
  uc[2] = temp;
}


But the server now gets 8.47518e+11 and Windows gets 0.0.
The struct is packed and it still gives me the wrong result.

#if !defined( _SERVER )
#pragma pack(push, 1)
#endif
typedef struct
{
  unsigned char type;
  float version;
  char username[16];
  char password[16];
}
#if defined( _SERVER )
__attribute__ ((packed))
#endif
LoginPacket;
#if !defined( _SERVER )
#pragma pack(pop)
#endif


The client sends 37 bytes and server receives 37 bytes.

The server sends back this:

#if !defined( _SERVER )
#pragma pack(push, 1)
#endif
typedef struct
{
unsigned char type;
float version;
} 
#if defined( _SERVER )
__attribute__ ((packed))
#endif
WrongVersionPacket;
#if !defined( _SERVER )
#pragma pack(pop)
#endif

The server says it sends 8 bytes for some reason and the client receives 8. I don't know why it's 8... should be 5. Is a float 7 bytes on Amazon Linux?

Edited by polyfrag, 03 July 2012 - 10:36 AM.


Sponsor:

#2 mrjones   Members   -  Reputation: 612

Like
0Likes
Like

Posted 03 July 2012 - 10:55 AM

You might try checking what is the standard used by the compilers on both systems. Although I'd not use floating point for data that is sent over the network. It's a can of worms in general. It's better to send the floating point as a string or send fixed a point number, if it isn't vital to send a floating point number. If you specifically need to send floating point numbers, it might be better to use protobuf or some other library that handles the differences internally.

#3 hplus0603   Moderators   -  Reputation: 5157

Like
2Likes
Like

Posted 03 July 2012 - 11:33 AM

Your problem is probably in the struct packing of the different compilers, not in the byte representation of the floats. In fact, I think your pack push/pop is causing the problem, because GCC doesn't care about those directives.
Most EC2 servers and most Windows machines use the x86 or x86/64 hardware platform, which encodes floats the same -- as IEEE-753 4-byte little-endian values.

The easiest way to make structs largely the same across compilers is to sort your data members from largest natural alignment to smallest -- first double, then int64, then pointer, then size_t, then float, then int, then short, then char.
If you don't want to re-order the struct members, then the second option is to go through a marshalling/de-marshalling library, rather than doing straight byte copies.

enum Bool { True, False, FileNotFound };

#4 frob   Moderators   -  Reputation: 20169

Like
3Likes
Like

Posted 03 July 2012 - 12:24 PM

Seconding the marshaling system.

The x86 platform is one of the few that allows mismatched alignment of integers and floats. Most other systems will crash on misaligned data. Even the x86 stopped supporting misaligned data with the newer extended data types; anything after '95 such as the 128-bit packed types.

A marshaling system will ensure that you don't violate alignment constraints which could crash your app.

Edited by frob, 03 July 2012 - 12:25 PM.

Check out my personal indie blog at bryanwagstaff.com.

#5 polyfrag   Crossbones+   -  Reputation: 1822

Like
0Likes
Like

Posted 03 July 2012 - 06:46 PM

Oh, wide char

#6 hplus0603   Moderators   -  Reputation: 5157

Like
0Likes
Like

Posted 03 July 2012 - 07:16 PM

There is no wide char in your struct; it has nothing to do with the problem as posted.
enum Bool { True, False, FileNotFound };

#7 Sik_the_hedgehog   Crossbones+   -  Reputation: 1601

Like
0Likes
Like

Posted 04 July 2012 - 04:27 AM

I'd treat sending data through a network the same way as storing data in files, i.e. don't trust anything about whoever else may end up accessing the data, only process raw unsigned bytes and nothing else, and use that as a basis for other types (larger integers, floating point, strings, etc.).
Don't pay much attention to "the hedgehog" in my nick, it's just because "Sik" was already taken =/ By the way, Sik is pronounced like seek, not like sick.

#8 polyfrag   Crossbones+   -  Reputation: 1822

Like
0Likes
Like

Posted 04 July 2012 - 05:39 PM

There is no wide char in your struct; it has nothing to do with the problem as posted.

It's using 4 bytes per char like in Java

#9 Nypyren   Crossbones+   -  Reputation: 4139

Like
1Likes
Like

Posted 04 July 2012 - 07:37 PM

That is incorrect. The char is still only 1 byte. There are 3 bytes of padding due to struct alignment for the following member (the float).

Put 4 chars in a struct all by themselves and your struct will only be 4 bytes in size.

Edited by Nypyren, 04 July 2012 - 07:37 PM.


#10 polyfrag   Crossbones+   -  Reputation: 1822

Like
0Likes
Like

Posted 04 July 2012 - 07:53 PM

I changed it to uint8_t and it works

#11 hplus0603   Moderators   -  Reputation: 5157

Like
1Likes
Like

Posted 04 July 2012 - 11:09 PM

The size of char in C and C++ is well defined to be the smallest addressable unit of memory. Unless you're running on some exotic DSP architecture, where everything is a full word in size, a char is 8 bits. And sizeof(char) is defined to be 1 -- that's the definition of what "sizeof" is expressed in.
If you believe that the only change you made was changing from "char" to "uint8_t" and it suddenly changed struct alignment, then I suggest you look a lot deeper for the real cause and solution.
enum Bool { True, False, FileNotFound };

#12 Tribad   Members   -  Reputation: 841

Like
0Likes
Like

Posted 05 July 2012 - 01:40 AM

Sign extent?
A signed data type is extended into a larger format, e.g. from byte to int or int to long, by copying the sign (MSB) bit into the new upper bits of the new format. This is valid for all all integer datatypes.

Edited by Tribad, 05 July 2012 - 01:41 AM.





Old topic!
Guest, the last post of this topic is over 60 days old and at this point you may not reply in this topic. If you wish to continue this conversation start a new topic.



PARTNERS