Boost logo

Boost :

From: Borgerding, Mark A. (MarkAB_at_[hidden])
Date: 2000-03-10 15:51:24


I had an idea today for a way to more easily write portable networking code.

The concept is a wrapper around an integer type that automatically convert
to/from the desired byte order.
The class has no virtual functions and is the same size as the contained
type. i.e. sizeof( big_endian<int> == sizeof(int) )
The rationale behind this is to make it easy to write something like

struct ProtocolHeader
{
        big_endian<uint16> crc; // 2 bytes, in network byte order
        big_endian<uint16> packetlength;// 2 bytes, in network byte order
        big_endian<uint32> sequenceNum;// 4 bytes, in network byte order
};

This way the integer type could be stored in the appropriate binary form,
without needing to worry about ntoh and hton conversions. An entire
ProtocolHeader struct object could be written to disk, socket, or whatever
without needing to perform any byte order conversions.

The implementation is really simple. The only operation allowed for
big_endian<T> is conversion to a const T. If this is done, everything seems
to fall into place nicely. It allows most things you could do with a builtin
type, except for non-const operators like --,++,+=,-=, and so on.
Assignment is easy because a temporary object is constructed from the
primitive type to use the implicit assignment operator.

It allows you to treat the object almost exactly like the corresponding
primitive, eg.

        big_endian<uint32> nbo = 5;
        nbo = nbo * 2;

What is actually happening in the above example (for an x86 machine) is:
line 1: nbo is constructed with a buffer of 0x05000000 (remember, it's
little endian), the value stored in nbo is 0x00000005 (big endian)
line 2: big_endian<uint32>::operator const uint32() is called which converts
the stored member back to little endian, the result is multiplied by two and
then a temporary big_endian<uint32> is constructed and assigned into nbo
(via implicitly declared assignment op).

I was worried about the cost of unnecessarily converting back and forth
between byte orders. But the preliminary tests I've done show no
appreciable difference between doing operations with a big_endian<unsigned
int> or an unsigned int directly. The test file is attached.

endian.hpp -- The implementation of the big_endian and little_endian
templates.
byteorder.cpp -- The test file.





Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk