Elegantly Handling Endianess in C++
On my current project, the network endianess is the opposite of the machine's endianess that I am working on. This means my usual game of just casting the bytes to a struct containing the packet format is out of the question. Does anybody know of an elegant method of handling this problem in C++ or even OS wise? I am working on an SGI Onyx running IRIX 6.5. Surely there is something better than manual byte swapping.
The most elegant way is the Boost Serialization Library, afaik.
Or something similar but home-made and more limited but perhaps more intuitive, such as a save( ostream &, T const & ) and load( istream &, T & ). You'd define it in an endian-safe way for the built-in types and then implement it for the others in terms of the basic ones.
Note also that casting to struct has its problems even without the endianness ones...
Or something similar but home-made and more limited but perhaps more intuitive, such as a save( ostream &, T const & ) and load( istream &, T & ). You'd define it in an endian-safe way for the built-in types and then implement it for the others in terms of the basic ones.
Note also that casting to struct has its problems even without the endianness ones...
Ooo, The Code Project has a nice article on endianess.
This will have to work for now. Not as elegant as I would ideally like, but I'm also not interested in going for a 'heavy weight' solution.
#include <algorithm> //required for std::swap#define ByteSwap5(x) ByteSwap((unsigned char *) &x,sizeof(x))void ByteSwap(unsigned char * b, int n){ register int i = 0; register int j = n-1; while (i<j) { std::swap(b, b[j]); i++, j--; }}
This will have to work for now. Not as elegant as I would ideally like, but I'm also not interested in going for a 'heavy weight' solution.
You don't need to care about the network endian-ness, except for the case of filling out the socket address. You can send un-swapped data just fine across the network -- assuming that the destination machine uses the same endian-ness as the sender.
enum Bool { True, False, FileNotFound };
Quote:
Original post by hplus0603
You don't need to care about the network endian-ness, except for the case of filling out the socket address. You can send un-swapped data just fine across the network -- assuming that the destination machine uses the same endian-ness as the sender.
By standardization on the project, data is sent across the network using big endian. My machine is little endian.
This is my idea:
NetworkType encapsulates a single value. Operator overloading is used to catch assignment and so on and perform conversion.
NetworkTraits are used to determine at compile-time if conversion should happen. Since you said you have to use big-endian as network default, only in the little-endian version of NetworkTraits a conversion actually occurs.
And swap_bytes performs this conversion.
Note that every access to the variable might require a conversion of the byte order.
[Edited by - nmi on May 8, 2005 4:26:36 AM]
#include <stdio.h>// compile-time settings for endianessenum { BIG_ENDIAN = 0, LITTLE_ENDIAN = 1, HOST_ENDIANESS = LITTLE_ENDIAN};// this class swaps the bytes of a valuetemplate <unsigned N, unsigned I = N>struct swap_bytes{ static inline void swap(char* dst, char* src) { dst[N-I] = src[I-1]; swap_bytes<N, I-1>::swap(dst, src); }};template <unsigned N>struct swap_bytes<N, 0>{ static inline void swap(char* dst, char* src) { }};// for little endian, define how to convert data// between network type and host typetemplate <typename T, bool IS_LITTLE_ENDIAN>struct NetworkTraits{ // convert byte order static inline T convert(T value) { // swap byte values T new_value; swap_bytes<sizeof(T)>::swap((char*)&new_value, (char*)&value); return new_value; }};// for big endian define how to convert data// between network type and host typetemplate <typename T>struct NetworkTraits<T, false>{ // convert byte order static inline T convert(T value) { // for big-endian this is a no-op return value; }};// this class encapsulates a single value// due to operator overloading, a value is converted on read/writetemplate <typename T>struct NetworkType { T value; NetworkType& operator= (T new_value) { value = NetworkTraits<T, HOST_ENDIANESS>::convert(new_value); return *this; } // overload other operators ...};int main(){ printf("starting\n"); if (HOST_ENDIANESS == LITTLE_ENDIAN) { printf("is little endian\n"); } NetworkType<unsigned int> i; i = 0x01020304; printf("%x\n", i.value); printf("finished\n"); return 0;}
NetworkType encapsulates a single value. Operator overloading is used to catch assignment and so on and perform conversion.
NetworkTraits are used to determine at compile-time if conversion should happen. Since you said you have to use big-endian as network default, only in the little-endian version of NetworkTraits a conversion actually occurs.
And swap_bytes performs this conversion.
Note that every access to the variable might require a conversion of the byte order.
[Edited by - nmi on May 8, 2005 4:26:36 AM]
Yeah the only Big Endian you'll probably ever encounter is the PowerPC and the Solaris Sparc so if you aren't planning on having any of those running your program you're absolutely fine. [edit: so sorry i completely missed your last sentence where you say what you are running]
Incidently, there is a function for linux/windows called htonl, htons for converting from host order to network order and ntohl, ntohs for converting from network to host. The l and s stand for long (32-bit) and short (16-bit) integers. Do a google for the libraries that you have to include.
Incidently, there is a function for linux/windows called htonl, htons for converting from host order to network order and ntohl, ntohs for converting from network to host. The l and s stand for long (32-bit) and short (16-bit) integers. Do a google for the libraries that you have to include.
here you go
http://techpubs.sgi.com/library/tpl/cgi-bin/getdoc.cgi?coll=0530&db=man&fname=/usr/share/catman/p_man/cat3c/byteorder.z
http://techpubs.sgi.com/library/tpl/cgi-bin/getdoc.cgi?coll=0530&db=man&fname=/usr/share/catman/p_man/cat3c/byteorder.z
Quote:
Original post by Hexxagonal
btw an Irix is big endian i just checked... just like network ordering
You're right, I swapped my message earlier. Network data is little, machine is big. In any case, I ended up using a similiar idea to the function I posted earlier. I just used a templated helper function instead of a macro.
This topic is closed to new replies.
Advertisement
Popular Topics
Advertisement
Recommended Tutorials
Advertisement