Table of Contents
Endian Template (C++)
Work with big endian and little endian types in C++ without ever calling an "endian swap" function
License
- Author: Terence J. Grant
- License: MIT License
- Last Update: 2016-02-26
- Donate: Your donations are appreciated!
Download
Before downloading or using this product, make sure you understand and accept the terms of the license.
After downloading, make sure to follow the how to use instructions below; they're worth reading.
- Latest version: Endian Template(C++) version 2016-02-26 on GitHub
About
The Endian Template is a set of C++ template class and typedefs that allow you use little endian or big endian types, without having to write or concern yourself with "endian swap" functions, on any platform that supports at least the C++98 standard.
This provides a few benefits over other techniques:
- Guaranteed endian correctness when using a typedef
- No need to call "endian swap" functions
- No need for "endian detection macros", as everything is determined at compile-time / run-time
- Ability to wrap your own types with the provided templates
How to Use
Setup
- First, copy the header
tEndian.h
into your project. - Next, include the header somewhere in your project or precompiled header if you use one.
#include "tEndian.h"
Typedefs
You'll now have the following typedefs to use in your project:
leint16
,leint32
,leint64
- Little endian signed typesleuint16
,leuint32
,leuint64
- Little endian unsigned typeslefloat32
,lefloat64
- Little endian floating point types
beint16
,beint32
,beint64
- Big endian signed typesbeuint16
,beuint32
,beuint64
- Big endian unsigned typesbefloat32
,befloat64
- Big endian floating point types
The naming conventions are based on those in C++ standard library header cstdint; the only addition being a prefix of le
or be
to indicate little endian or big endian, respectively.
Templates
You'll also have the following template classes available for use in your project:
tLittleEndian<T>
- Little endian template wrappertBigEndian<T>
- Big endian template wrapper
With those template wrappers, you could in theory wrap your own types.
For instance, if you wanted to define a big endian version of size_t
and short
, and a little endian version long long
, the following example code will achieve this:
typedef tBigEndian<size_t> besize; typedef tBigEndian<short> beshort; typedef tLittleEndian<long long> lelonglong;
You will also find a third template, tEndianBase<T>
, however it's only meant to be used as a helper class from the other template classes, so I don't suggest you use it directly yourself.
Usage
When using the endian types, you can literally just drop them in to replace your current types, as long as you also remove any endian swapping functions you're calling.
There are three primary reasons I see someone using the Endian Template:
- You're writing an emulator / virtual machine
- You're writing a binary file format reading / writing library
- Converting data sent over a network
I'll cover these three use cases, but forgive me as I'll be very brief with each.
Emulator / Virtual Machine
Of course, depending on the machine type, memory itself will be stored as big or little endian. However, it's typically when you're loading memory into registers, then doing math on those registers, when endianness starts to matter.
That said, you could define each register as the proper endian type for the platform you're emulating, and you won't have to worry or remember about shifting memory one way or another after a math operation– it just gets stored correctly on it's own.
Binary file formats
Binary formats are compact but are a potential minefield when dealing with different CPU architectures. The Endian Template can help here too.
I used to love writing things like image decoders for formats like BMP and the like. For example, in a BMP file, the first two bytes are typically BM
, but the next four bytes are "the size of the BMP file"– in little endian format.
If you read this data into an uint32_t
, you're fine as long as you're on a little endian machine (like an x86-based PC.) Not so much if you end up running your code on a PowerPC CPU, which is big endian.
So take the guesswork out of the equation– read it into an leuint32
instead and it'll always work, regardless of the architecture.
Sending data over a network
If you're familiar with Network Byte Order, you'll know that the functions htons
, htonl
, ntohl
, ntohs
are generally suggested to use before sending data over a network.
Since "Network Byte Order" is just "big endian"; instead you can now just define your data as beint32
, beint16
, or tBigEndian<unsigned short>
and discard the conversion functions completely.
And regardless of the endian of computer's CPU, the code will always work.
Running the unit tests
The Endian Template comes with a unit test class, tEndianTests.cc
, and three project files:
/project/win/EndianTests.sln
- Visual Studio 2005, Windows console target/project/mac/EndianTests.xcodeproject
- Xcode 7 Mac OS console target/project/ios/EndianTests.xcodeproject
- Xcode 7 iOS console target
When running the unit test on Visual Studio, note you will first need to convert the solution to the latest version. You'll also need to put a breakpoint on the last line of the main
function, as the console window containing the results of the test will close on exit.
When running the unit test on Mac or for iOS, the results of the test will be printed in Xcode's debug console, which is at the bottom right of Xcode's window.
Also, when running for iOS, you'll note that an app won't appear or launch in the simulator or on a device, as the tests are purely meant to display in the debug console.
(If you're curious, these project files were generated with Google GYP; the source project file is located in /project/common/EndianTests.gyp
.)
Q & A
If you have a question not answered here, please feel free to contact me and ask.
vs Boost?
- Q: What makes this better or different than Boost.Endian?
- A: I can't say for certain if it's better. The Endian Template is small, and only provides a minimum of what's needed to handle automatic endian conversion.
As I understand it Boost.Endian provides three different mechanisms for handling endian (one providing swapping functions), whereas my primary philosophy here is "don't use swapping functions."
Just for trivia: I originally created this class in 2001 as a proof-of-concept, hoping I could use it in some emulation projects (never got around to those unfortunately.) This predates when Boost.Endian came out, which was around 2002 or 2003.
That said, I've used boost (in general) before on a day-to-day basis for a client project. I'm not a boost "hater", but I'm not a regular user of it either.
History
February 26, 2016
- Renamed typedefs without
_t
postfix notation as this appears to be "reserved" by POSIX (thanks to reddit user "doodle77") - Added required includes directly into
tEndian.h
(thanks to reddit user "louiswins") - Changed endian testing method to use reinterpret_cast, as the previous was using "type punning", which in theory can have undefined behavior (thanks to reddit user "NasenSpray")
- Removed ::PassThru method as a small optimization
February 23, 2016
- Added GitHub link to download section
- First public release
- Created project page