-
September 23rd, 2010, 10:38 AM
#1
endianness questions
Hello,
I am receiving data in Network Byte Order (big endian) and I am on an Intel machine so I am converting it to Little Endian.
1. I get this error when trying to convert 32 bit values:
Code:
float position;
memcpy(&position, &message[0], 4); // message is of type vector<char>
position=ntohl(position);
warning C4244: 'argument' : conversion from 'float' to 'u_long', possible loss of data
Am I doing something worng here?
2. When I use structures I get an error:
Code:
struct data
{
unsigned short int temp: 16;
unsigned short int flag : 1;
unsigned short int temp2: 15;
} dat;
bool flag_;
memcpy(&dat, &message[4], 4);
dat=ntohl(dat);
flag_=dat.flag;
error C2664: 'ntohl' : cannot convert parameter 1 from CTest:ata' to 'u_long'
How can I fix these issues?
Thanks!
-
September 23rd, 2010, 11:23 AM
#2
Re: endianness questions
1. It is NOT an "error", it is a "warning" which meaning is very clear:
there may be "loss of data" if your position > 4294967295
To fix it - don't use float, use u_long instead (or just ignore this warning!)
2. This error is also very clear: compiler has no idea how to convert your struct data to 'u_long'.
To fix it you could implement a union of this structure with a u_long variable. See the example in Union Declarations
Victor Nijegorodov
-
September 23rd, 2010, 12:40 PM
#3
Re: endianness questions
Hey Victor,
2. But in the struct I only need access to one bit. Can I do something like this?
Code:
union
{
struct data
{
unsigned short int temp: 16;
unsigned short int flag : 1;
unsigned short int temp2: 15;
} dat;
u_long data1;
} dataun;
bool flag_;
memcpy(&dataun.dat, &message[4], 4);
dataun.data1=ntohl(dataun.data1);
flag_=dataun.dat.flag;
Is that correct?
Also, why dont I see a "u_long" type on this site? http://msdn.microsoft.com/en-us/libr...tz(VS.80).aspx
How big is a u_long as compared to a float?
Thanks!
Last edited by lab1; September 23rd, 2010 at 12:43 PM.
-
September 23rd, 2010, 12:48 PM
#4
Re: endianness questions
Originally Posted by lab1
u_long is presumably a typedef of unsigned long.
Unfortunately, how large that is depends on the OS. On Windows (both 32-bit and 64-bit), it's 4 bytes, same as a float. But on 64-bit linux (and, I think, 64-bit OSX), an unsigned long is 8 bytes.
If you want to write a generic ntoh(), you can do it:
Code:
template <typename T>
T ntoh(T networkorder)
{
if (ntohs(1) == 1)
return networkorder;
char bytes[sizeof(T)];
memcpy(bytes,&networkorder);
std::reverse(bytes,bytes+sizeof(T));
return *(reinterpret_cast<T*>(bytes));
}
There may be a better way to make this a pass-through in the cast of a BE machine, but it's at least possible that the if statement would be evaluated at compile time.
Last edited by Lindley; September 23rd, 2010 at 12:53 PM.
-
September 23rd, 2010, 12:53 PM
#5
Re: endianness questions
Originally Posted by lab1
2. But in the struct I only need access to one bit. Can I do something like this?
....
Is that correct?
Why didn't you try it?
Originally Posted by lab1
Are you using a Microsoft compiler?
And I guess u_long is 4 bytes long (i.e. 32 bit). It is the same as float but unsigned long can represent numbers between 0 and 4294967295 while float (according to MSDN) - between 1.175494351e-38F and 3.402823466e+38F
Victor Nijegorodov
-
September 23rd, 2010, 01:44 PM
#6
Re: endianness questions
Why does ntohl() return a unsigned long? What if the value is negative?
Thanks
-
September 23rd, 2010, 02:07 PM
#7
Re: endianness questions
Originally Posted by lab1
Why does ntohl() return a unsigned long? What if the value is negative?
Thanks
Once you start doing endianness conversions, the value doesn't matter anymore, only the bit pattern. The value of the bit pattern is only meaningful in the host byte order.
If the value is intended to be negative, then casting the result to int should recover that.
-
September 23rd, 2010, 02:17 PM
#8
Re: endianness questions
Hey Lindley,
Why does this code end up with leTest as "227.0" then?
Code:
#include "winsock2.h"
int main()
{
float test = -30.0;
float beTest = htonl(test);
float leTest = (float)ntohl(beTest);
}
By the way, the code is executed ona intel (little endian) machine.
Thanks!
Last edited by lab1; September 23rd, 2010 at 02:22 PM.
-
September 23rd, 2010, 02:25 PM
#9
Re: endianness questions
Because conversion between floating types and integer types tries to preserve values rather than bit patterns. Try this instead:
Code:
#include "winsock2.h"
int main()
{
float test = -30.0;
unsigned long betest = htonl(*reinterpret_cast<unsigned long*>(&test));
unsigned long letest = ntohl(betest);
float leFloatTest = *reinterpret_cast<float*>(&letest);
}
-
September 23rd, 2010, 02:29 PM
#10
Re: endianness questions
That works. Can you explain why:
Code:
float leFloatTest = (float)letest;
doesnt work? Why the weird casting?
Also, any way I can condence these two lines into one line?
Code:
unsigned long letest = ntohl(betest);
float leFloatTest = *reinterpret_cast<float*>(&letest);
Thanks!
Last edited by lab1; September 23rd, 2010 at 02:46 PM.
-
September 23rd, 2010, 02:46 PM
#11
Re: endianness questions
Originally Posted by lab1
Can you explain why: (...) doesnt work? WHy the weird casting?
Recall what Lindley wrote in post #7:
Originally Posted by Lindley
Once you start doing endianness conversions, the value doesn't matter anymore, only the bit pattern.
-
September 23rd, 2010, 02:49 PM
#12
Re: endianness questions
Originally Posted by lab1
Also, any way I can condence these two lines into one line?
Sure, you can write a function:
Code:
template <typename To, typename From>
static inline To bitwise_cast(From from) {
BOOST_STATIC_ASSERT(sizeof(From) == sizeof(To));
union {
From f;
To t;
} u;
u.f = from;
return u.t;
}
-
September 23rd, 2010, 04:21 PM
#13
Re: endianness questions
Originally Posted by lab1
Code:
struct data
{
unsigned short int temp: 16;
unsigned short int flag : 1;
unsigned short int temp2: 15;
} dat;
Be aware that bitfields are not portable. If you use bitfields you have to be sure that the code on both sides have been compiled/linked with the same compiler/linker using the same flags and that the platforms are of the same type (CPU-family).
-
September 24th, 2010, 06:55 AM
#14
Re: endianness questions
Originally Posted by S_M_A
Be aware that bitfields are not portable. If you use bitfields you have to be sure that the code on both sides have been compiled/linked with the same compiler/linker using the same flags and that the platforms are of the same type (CPU-family).
Where in the C++ Standard does it say this? I thought it said exactly the oppossite.
-
September 24th, 2010, 06:49 PM
#15
Re: endianness questions
I don't have access to a release version of the standard but here's a fragment from http://www.open-std.org/jtc1/sc22/wg...2005/n1905.pdf (section 9.6)
A member-declarator of the form
identifieropt : constant-expression
specifies a bit-field; its length is set off from the bit-field name by a colon. The bit-field attribute is not part of the
type of the class member. The constant-expression shall be an integral constant-expression with a value greater than or
equal to zero. The constant-expression may be larger than the number of bits in the object representation (3.9) of the
bit-field’s type; in such cases the extra bits are used as padding bits and do not participate in the value representation
(3.9) of the bit-field. Allocation of bit-fields within a class object is implementation-defined. Alignment of bit-fields is
implementation-defined. Bit-fields are packed into some addressable allocation unit. [ Note: bit-fields straddle allocation
units on some machines and not on others. Bit-fields are assigned right-to-left on some machines, left-to-right on others.
—end note ]
Posting Permissions
- You may not post new threads
- You may not post replies
- You may not post attachments
- You may not edit your posts
-
Forum Rules
|
Click Here to Expand Forum to Full Width
|