Little/big endian distinction within same application

Started by
8 comments, last by rip-off 12 years ago
Hello,

I am wondering if there is an elegant way of doing this:
In my application, which is supposed to run on more or less any type of hardware, I need to distinguish between that hardware's little/big endian, and the communication side of the application, which is in charge of sending little endian data to a PC.

What I would need is some sort of typedef based on the same type (e.g. 4-byte int) but that is mutually not compatible, e.g.

typedef int intLittle; //little endian
typedef int intSystem; // system's specific little or big endian

but following should produce a compilation error:

intLittle a=1;
intSystem b=a; // should generate a compilation error

Thanks for any insight!
Advertisement
For these kinds of "strong typedefs" I use something like:template<class T,class Name>
struct PrimitiveWrap
{
explicit PrimitiveWrap(T v) : value(v) {}
operator const T&() const { return value; }
operator T&() { return value; }
private:
T value;
};

struct LittleEndian_Tag {};
typedef PrimitiveWrap<int, LittleEndian_Tag> LittleEndian;
Thanks for the quick reply Hodgman,

I forgot to specify that the application should be C, not C++. Templates are unfortunately not available in C..
Your options are going to be pretty limited in C's comparatively weak type system. The closest thing I can think of would be to have something like this:

struct LittleEndian
{
int Value;
};

struct BigEndian
{
int Value;
};

typedef struct LittleEndian NativeEndian; // or BigEndian depending on platform


The syntactic overhead will be a bit annoying, as you'll have to access the value member all over the place, but... eh. The compiler should eliminate all the cost anyways, so it's strictly a matter of doing extra typing.

The other alternative that comes to mind is some macro magic:

#define MAKE_LITTLE_ENDIAN(x) (x)
#define MAKE_BIG_ENDIAN(x) ENDIAN_SWAP(x)
#define N(x) MAKE_LITTLE_ENDIAN(x)

/* And of course swap the above macros on big-endian platforms */

void NetworkTransmit(int native)
{
int little = MAKE_LITTLE_ENDIAN(native);
/* Do stuff */
}

int main()
{
int autoendian = N(42);

printf("Number: %d\n", autoendian);
NetworkTransmit(autoendian);
}

Wielder of the Sacred Wands
[Work - ArenaNet] [Epoch Language] [Scribblings]

I can suggest another option - make the PC do all the work.

To do that simply make the first thing you transmit a known magic number say 0x12345678 which the PC can use to determine the endianness of the system that sent it and perform the appropriate corrections.

All the other platforms then don't need to worry about endianness.
Thanks for the good ideas ApochPiQ and Adam_42. Strangely enough I didn't even think about that last idea of having the PC figure it out, which I will opt for, since I have more flexibility by doing it that way!

Thanks again!
While I am at it... there is however a thing that I will have to do on the c-side: figure out the floating-point type, and convert it to the one on the PC side. How would I best do that? i.e. have a portable floating point format?
Just out of curiosity, why don't you have both computers communicate in the normal networking way? htons(), htonl(), ntohs(), ntohl() (though you'll have to write your own 64 bit function if you need 64-bit ints).

And about the floating point stuff... you should pick the hardware you'll support, and then write to support that hardware. If you don't do that and you want to support everything under the sun (including non-IEEE 754 formats, though that's not legal C then), you have to send data as text (or some other intermediary format) and then convert it on both ends. 99% of computers (that's a made up stat, but I wouldn't be surprised if it's close) use little-endian IEEE 754 floats, so it's not like you'll be missing a big market there if you say only little-endian IEEE 754 floats are supported. Also, read this: http://en.wikipedia...._and_endianness

But of course, since C is going to use IEEE 754, you could also send a special float at the beginning that will inform the server of the computer's endianness. Something like -3.0f should be enough. OR you could just make your own htonf(), htond(), ntohf(), ntohd() (host to network float, host to network double, etc) and use them. But if you're seriously going to be this pedantic about things, you should also be pedantic about the size of bytes on a system (CHAR_BIT does not have to be 8), and the number of bytes in int, short, long, etc.
[size=2][ I was ninja'd 71 times before I stopped counting a long time ago ] [ f.k.a. MikeTacular ] [ My Blog ] [ SWFer: Gaplessly looped MP3s in your Flash games ]
For endianess, in C, it would work like that:#ifdef PLATFORM1
#define TONETWORK(x) ...
#define FROMNETWORK(x) ...
#elseif PLATFORM1
#define TONETWORK(x) ...
#define FROMNETWORK(x)
... undefined otherwise

However, OSes already come with hton... functions, so it's mostly a solved problem.


How would I best do that? i.e. have a portable floating point format?


Is this an important problem or a non-issue. Worrying about floating point format on PC is not really important.


Again, solution is simple:#ifdef PLATFORM1

void pack_float(void * dst, void * src);
void unpack_float(void * dst, void * src);

#elseif ...
Provide one conversion function for each.

But floating point conversions like this are generally highly undesirable due to loss of accuracy. Writing algorithms which work robustly is hard enough when dealing with IEEE754, let along trying to work through different encodings.

Is zero signed or not? How is infinite represented? How are numbers normalized?

IEEE754 alone is covered in this document. Any other format will have similar complexity, bidirectional mapping from one to another is likely a PhD-grade material.

Floats are simply way too messy to approach casually. Prefer to simply not deal with that. And yes, issues are guaranteed to show up, better hope the data you're working with isn't important.
One option is to use a fixed point format for sending "float" data on the network.

This topic is closed to new replies.

Advertisement