====== Endian Template (C++) ====== //Work with big endian and little endian types in C++ without ever calling an "endian swap" function// ===== License ===== * **Author:** [[mailto:tjgrant@tatewake.com|Terence J. Grant]] * **License:** [[http://opensource.org/licenses/MIT|MIT License]] * **Last Update:** 2016-02-26 * **Donate:** [[: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|how to use]] instructions below; they're worth reading. * Latest version: [[https://github.com/tatewake/endian-template|Endian Template(C++) version 2016-02-26 on GitHub]] ===== About ===== The Endian Template is a set of [[wp>Template_(C%2B%2B)|C++ template class]] and [[wp>Typedef|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 [[wp>Precompiled_header|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 types * ''leuint16'', ''leuint32'', ''leuint64'' - Little endian unsigned types * ''lefloat32'', ''lefloat64'' - Little endian floating point types * ''beint16'', ''beint32'', ''beint64'' - Big endian signed types * ''beuint16'', ''beuint32'', ''beuint64'' - Big endian unsigned types * ''befloat32'', ''befloat64'' - Big endian floating point types The naming conventions are based on those in C++ standard library header [[http://en.cppreference.com/w/cpp/header/cstdint|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'' - Little endian template wrapper * ''tBigEndian'' - 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 besize; typedef tBigEndian beshort; typedef tLittleEndian lelonglong; You will also find a third template, ''tEndianBase'', 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 [[wp>BMP_file_format|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 [[http://www.tutorialspoint.com/unix_sockets/network_byte_orders.htm|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'' 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 [[wp>GYP_(software)|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 [[mailto:tjgrant@tatewake.com|contact me]] and ask.// === vs Boost? === * **Q:** What makes this better or different than [[http://www.boost.org/libs/endian/|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