forked from boostorg/endian
git-svn-id: http://svn.boost.org/svn/boost/sandbox/endian@62439 b8fc166d-592f-0410-95f2-cb63ce0dd405
664 lines
33 KiB
HTML
664 lines
33 KiB
HTML
<html>
|
|
|
|
<head>
|
|
<meta http-equiv="Content-Language" content="en-us">
|
|
<meta name="GENERATOR" content="Microsoft FrontPage 5.0">
|
|
<meta name="ProgId" content="FrontPage.Editor.Document">
|
|
<meta http-equiv="Content-Type" content="text/html; charset=windows-1252">
|
|
<title>Boost Endian Integers</title>
|
|
<link rel="stylesheet" type="text/css" href="../../../doc/html/minimal.css">
|
|
</head>
|
|
|
|
<body>
|
|
|
|
|
|
<table border="0" cellpadding="5" cellspacing="0" style="border-collapse: collapse" bordercolor="#111111" width="710">
|
|
<tr>
|
|
<td width="277">
|
|
<a href="../../../index.html">
|
|
<img src="../../../boost.png" alt="boost.png (6897 bytes)" align="middle" width="277" height="86" border="0"></a></td>
|
|
<td width="413" align="middle">
|
|
<font size="7">Endian Integers</font>
|
|
</td>
|
|
</tr>
|
|
</table>
|
|
|
|
<table border="0" cellpadding="5" cellspacing="0" style="border-collapse: collapse" bordercolor="#111111" bgcolor="#D7EEFF" width="100%">
|
|
<tr>
|
|
<td><a href="../../../index.htm">Boost Home</a> Tutorial</td>
|
|
</tr>
|
|
</table>
|
|
|
|
<table border="1" cellpadding="5" cellspacing="0" style="border-collapse: collapse" bordercolor="#111111" align="right">
|
|
<tr>
|
|
<td width="100%" bgcolor="#D7EEFF" align="center">
|
|
<i><b>Contents</b></i></td>
|
|
</tr>
|
|
<tr>
|
|
<td width="100%" bgcolor="#E8F5FF">
|
|
<a href="#Introduction">Introduction</a><br>
|
|
<a href="#Hello-endian-world">Hello endian world</a><br>
|
|
<a href="#Limitations">Limitations</a><br>
|
|
<a href="#Feature-set">Feature set</a><br>
|
|
<a href="#Types">Typedefs</a><br>
|
|
<a href="#Comment-on-naming">Comment on naming</a><br>
|
|
<a href="#Class_template_endian">Class template <code>endian</code></a><br>
|
|
|
|
<a href="#Synopsis">Synopsis</a><br>
|
|
<a href="#Members">Members</a><br>
|
|
<a href="#FAQ">FAQ</a><br>
|
|
<a href="#Binary-I-O-cautions">Binary I/O warnings and cautions</a><br>
|
|
<a href="#Example">Example</a><br>
|
|
<a href="#Design">Design</a><br>
|
|
<a href="#Experience">Experience</a><br>
|
|
<a href="#Motivating-use-cases">Motivating use cases</a><br>
|
|
<a href="#C++0x">C++0x</a><br>
|
|
<a href="#Compilation">Compilation</a><br>
|
|
<a href="#Acknowledgements">Acknowledgements</a>
|
|
</td>
|
|
</tr>
|
|
<tr>
|
|
<td width="100%" bgcolor="#D7EEFF" align="center">
|
|
<b><i>Headers</i></b></td>
|
|
</tr>
|
|
<tr>
|
|
<td width="100%" bgcolor="#E8F5FF">
|
|
<a href="../../../boost/integer/endian.hpp"><boost/integer/endian.hpp></a><br>
|
|
<a href="../../../boost/integer/endian_binary_stream.hpp"><boost/integer/endian_binary_stream.hpp></a><br>
|
|
<a href="../../../boost/binary_stream.hpp"><boost/binary_stream.hpp></a></td>
|
|
</tr>
|
|
</table>
|
|
<h2><a name="Introduction">Introduction</a></h2>
|
|
<p>Header
|
|
<a href="../../../boost/integer/endian.hpp"><boost/integer/endian.hpp></a> provides
|
|
integer-like byte-holder binary types with explicit control over
|
|
byte order, value type, size, and alignment. Typedefs provide easy-to-use names
|
|
for common configurations.</p>
|
|
<p>These types provide portable byte-holders for integer data, independent of
|
|
particular computer architectures. Use cases almost always involve I/O, either via files or
|
|
network connections. Although data portability is the primary motivation, these
|
|
integer byte-holders may
|
|
also be used to reduce memory use, file size, or network activity since they
|
|
provide binary integer sizes not otherwise available.</p>
|
|
<p>Such integer byte-holder types are traditionally called <b><i>
|
|
endian</i></b> types. See the <a href="http://en.wikipedia.org/wiki/Endian">Wikipedia</a> for
|
|
a full
|
|
exploration of <b><i>endianness</i></b>, including definitions of <i><b>big
|
|
endian</b></i> and <i><b>little endian</b></i>.</p>
|
|
<p>Boost endian integers provide the same full set of C++ assignment,
|
|
arithmetic, and relational operators as C++ standard integral types, with
|
|
the standard semantics.</p>
|
|
<p>Unary arithmetic operators are <code>+</code>, <code>-</code>, <code>~</code>,
|
|
<code>!</code>, prefix and postfix <code>--</code> and <code>++</code>. Binary
|
|
arithmetic operators are <code>+</code>, <code>+=</code>, <code>-</code>, <code>
|
|
-=</code>, <code>*</code>, <code>*=</code>, <code>/</code>, <code>/=</code>,
|
|
<code>%/ %=</code>, <code>&</code>, <code>&=</code>, <code>|</code>, <code>|=</code>,
|
|
<code>^</code>, <code>^=</code>, <code><<</code>, <code><<=</code>, <code>>></code>,
|
|
<code>>>=</code>. Binary relational operators are <code>==</code>, <code>!=</code>,
|
|
<code><</code>, <code><=</code>, <code>></code>, <code>>=</code>.</p>
|
|
<p>Automatic conversion is provided to the underlying integer value type.</p>
|
|
<p>Header <a href="../../../boost/integer/endian_binary_stream.hpp"><boost/integer/endian_binary_stream.hpp></a>
|
|
provides operators <= and <code>=></code> for unformatted binary (as opposed to
|
|
formatted character) stream insertion and extraction of endian types.</p>
|
|
<p>Header <a href="../../../boost/binary_stream.hpp"><boost/binary_stream.hpp></a>
|
|
provides operators <= and <code>=></code> for unformatted binary (as opposed to
|
|
formatted character) stream insertion and extraction of built-in and std::string
|
|
types.</p>
|
|
<h2><a name="Hello-endian-world">Hello endian world</a></h2>
|
|
<blockquote>
|
|
<pre>#include <boost/integer/endian.hpp>
|
|
#include <boost/integer/endian_binary_stream.hpp>
|
|
#include <boost/binary_stream.hpp>
|
|
#include <iostream>
|
|
|
|
using namespace boost;
|
|
using namespace boost::integer;
|
|
|
|
int main()
|
|
{
|
|
int_least32_t v = 0x31323334L; // = ASCII { '1', '2', '3', '4' }
|
|
// value chosen to work on text stream
|
|
big32_t b(v);
|
|
little32_t l(v);
|
|
|
|
std::cout << "Hello, endian world!\n\n";
|
|
|
|
std::cout << v << ' ' << b << ' ' << l << '\n';
|
|
std::cout <= v <= ' ' <= b <= ' ' <= l <= '\n';
|
|
}</pre>
|
|
</blockquote>
|
|
<p>On a little-endian CPU, this program outputs:</p>
|
|
<blockquote>
|
|
<pre>Hello, endian world!
|
|
|
|
825373492 825373492 825373492
|
|
4321 1234 4321</pre>
|
|
</blockquote>
|
|
<h2><a name="Limitations">Limitations</a></h2>
|
|
<p>Requires <code><climits></code> <code>CHAR_BIT == 8</code>. If <code>CHAR_BIT</code>
|
|
is some other value, compilation will result in an <code>#error</code>. This
|
|
restriction is in place because the design, implementation, testing, and
|
|
documentation has only considered issues related to 8-bit bytes, and there have
|
|
been no real-world use cases presented for other sizes.</p>
|
|
<p>In C++03, <code>endian</code> does not meet the requirements for POD types
|
|
because it has constructors, private data members, and a base class. This means
|
|
that common use cases are relying on unspecified behavior in that the C++
|
|
Standard does not guarantee memory layout for non-POD types. This has not been a
|
|
problem in practice since all known C++ compilers do layout memory as if <code>
|
|
endian</code> were a POD type. In C++0x, it will be possible to specify the
|
|
default constructor as trivial, and private data members and base classes will
|
|
no longer disqualify a type from being a POD. Thus under C++0x, <code>endian</code>
|
|
will no longer be relying on unspecified behavior.</p>
|
|
<h2><a name="Feature-set">Feature set</a></h2>
|
|
<ul>
|
|
<li>Big endian| little endian | native endian byte ordering.</li>
|
|
<li>Signed | unsigned</li>
|
|
<li>Unaligned | aligned</li>
|
|
<li>1-8 byte (unaligned) | 2, 4, 8 byte (aligned)</li>
|
|
<li>Choice of integer value type</li>
|
|
</ul>
|
|
<h2><a name="Types">Typedefs</a></h2>
|
|
<p>One class template is provided:</p>
|
|
<blockquote>
|
|
<pre>template <<a href="#endianness">endianness</a>::enum_t E, typename T, std::size_t n_bytes,
|
|
<a href="#alignment">alignment</a>::enum_t A = alignment::unaligned>
|
|
class endian;
|
|
</pre>
|
|
</blockquote>
|
|
<p>Sixty typedefs, such as <code>big32_t</code>, provide convenient naming
|
|
conventions for common use cases:</p>
|
|
<blockquote>
|
|
<table border="1" cellpadding="5" cellspacing="0" style="border-collapse: collapse" bordercolor="#111111" width="49%">
|
|
<tr>
|
|
<td width="18%" align="center"><b><i>Name</i></b></td>
|
|
<td width="10%" align="center"><b><i>Endianness</i></b></td>
|
|
<td width="10%" align="center"><b><i>Sign</i></b></td>
|
|
<td width="15%" align="center"><b><i>Sizes in bits (n)</i></b></td>
|
|
<td width="49%" align="center"><b><i>Alignment</i></b></td>
|
|
</tr>
|
|
<tr>
|
|
<td width="18%"><code>big</code><b><i>n</i></b><code>_t</code></td>
|
|
<td width="10%"><code>big</code></td>
|
|
<td width="10%">signed</td>
|
|
<td width="15%">8,16,24,32,40,48,56,64</td>
|
|
<td width="49%"><code>unaligned</code></td>
|
|
</tr>
|
|
<tr>
|
|
<td width="18%"><code>ubig</code><i><b>n</b></i><code>_t</code></td>
|
|
<td width="10%"><code>big</code></td>
|
|
<td width="10%">unsigned</td>
|
|
<td width="15%">8,16,24,32,40,48,56,64</td>
|
|
<td width="49%"><code>unaligned</code></td>
|
|
</tr>
|
|
<tr>
|
|
<td width="18%"><code>little</code><i><b>n</b></i><code>_t</code></td>
|
|
<td width="10%"><code>little</code></td>
|
|
<td width="10%">signed</td>
|
|
<td width="15%">8,16,24,32,40,48,56,64</td>
|
|
<td width="49%"><code>unaligned</code></td>
|
|
</tr>
|
|
<tr>
|
|
<td width="18%"><code>ulittle</code><i><b>n</b></i><code>_t</code></td>
|
|
<td width="10%"><code>little</code></td>
|
|
<td width="10%">unsigned</td>
|
|
<td width="15%">8,16,24,32,40,48,56,64</td>
|
|
<td width="49%"><code>unaligned</code></td>
|
|
</tr>
|
|
<tr>
|
|
<td width="18%"><code>native</code><i><b>n</b></i><code>_t</code></td>
|
|
<td width="10%"><code>native</code></td>
|
|
<td width="10%">signed</td>
|
|
<td width="15%">8,16,24,32,40,48,56,64</td>
|
|
<td width="49%"><code>unaligned</code></td>
|
|
</tr>
|
|
<tr>
|
|
<td width="18%"><code>unative</code><i><b>n</b></i><code>_t</code></td>
|
|
<td width="10%"><code>native</code></td>
|
|
<td width="10%">unsigned</td>
|
|
<td width="15%">8,16,24,32,40,48,56,64</td>
|
|
<td width="49%"><code>unaligned</code></td>
|
|
</tr>
|
|
<tr>
|
|
<td width="18%"><code>aligned_big</code><i><b>n</b></i><code>_t</code></td>
|
|
<td width="10%"><code>big</code></td>
|
|
<td width="10%">signed</td>
|
|
<td width="15%">16,32,64</td>
|
|
<td width="49%"><code>aligned</code></td>
|
|
</tr>
|
|
<tr>
|
|
<td width="18%"><code>aligned_ubig</code><i><b>n</b></i><code>_t</code></td>
|
|
<td width="10%"><code>big</code></td>
|
|
<td width="10%">unsigned</td>
|
|
<td width="15%">16,32,64</td>
|
|
<td width="49%"><code>aligned</code></td>
|
|
</tr>
|
|
<tr>
|
|
<td width="18%"><code>aligned_little</code><i><b>n</b></i><code>_t</code></td>
|
|
<td width="10%"><code>little</code></td>
|
|
<td width="10%">signed</td>
|
|
<td width="15%">16,32,64</td>
|
|
<td width="49%"><code>aligned</code></td>
|
|
</tr>
|
|
<tr>
|
|
<td width="18%"><code>aligned_ulittle</code><i><b>n</b></i><code>_t</code></td>
|
|
<td width="10%"><code>little</code></td>
|
|
<td width="10%">unsigned</td>
|
|
<td width="15%">16,32,64</td>
|
|
<td width="49%"><code>aligned</code></td>
|
|
</tr>
|
|
</table>
|
|
</blockquote>
|
|
<p>The unaligned types do not cause compilers to insert padding bytes in classes
|
|
and structs. This is an important characteristic that can be exploited to minimize wasted space in
|
|
memory, files, and network transmissions. </p>
|
|
<p><font color="#FF0000"><b><i><span style="background-color: #FFFFFF">Warning:</span></i></b></font><span style="background-color: #FFFFFF">
|
|
Code that uses a</span>ligned types is inherently non-portable because alignment
|
|
requirements vary between hardware architectures and because alignment may be
|
|
affected by compiler switches or pragmas. Furthermore, aligned types
|
|
are only available on architectures with 16, 32, and 64-bit integer types.</p>
|
|
<p><b><i>Note:</i></b> One-byte big-endian, little-endian, and native-endian types provide identical
|
|
functionality. All three names are provided to improve code readability and searchability.</p>
|
|
<h3><a name="Comment-on-naming">Comment on naming</a></h3>
|
|
<p>When first exposed to endian types, programmers often fit them into a mental model
|
|
based on the <code><cstdint></code> types. Using that model, it is natural to
|
|
expect a 56-bit big-endian signed integer to be named <code>int_big56_t</code>
|
|
rather than <code>big56_t</code>.</p>
|
|
<p>As experience using these type grows, the realization creeps in that they are
|
|
lousy arithmetic integers - they are really byte holders that for convenience
|
|
support arithmetic operations - and that for use in internal interfaces or
|
|
anything more than trivial arithmetic computations it is far better to convert
|
|
values of these endian types to traditional integer types.</p>
|
|
<p>That seems to lead to formation of a new mental model specific to endian byte-holder types. In that model, the endianness
|
|
is the key feature, and the integer aspect is downplayed.
|
|
Once that mental transition is made, a name like <code>big56_t</code> is a good
|
|
reflection of the mental model</p>
|
|
<h2><a name="Class_template_endian">Class template <code>endian</code></a></h2>
|
|
<p>An endian is an integer byte-holder with user-specified <a href="#endianness">
|
|
endianness</a>, value type, size, and <a href="#alignment">alignment</a>. The
|
|
usual operations on integers are supplied.</p>
|
|
<h3><a name="Synopsis">Synopsis</a></h3>
|
|
<pre>namespace boost
|
|
{
|
|
namespace integer
|
|
{
|
|
|
|
enum class <a name="endianness">endianness</a> { big, little, native }; // scoped enum emulated on C++03
|
|
enum class <a name="alignment">alignment</a> { unaligned, aligned }; // scoped enum emulated on C++03
|
|
|
|
template <endianness E, typename T, std::size_t n_bits,
|
|
alignment A = alignment::unaligned>
|
|
class endian : <a href="../../../boost/integer/cover_operators.hpp">integer_cover_operators</a>< endian<E, T, n_bits, A>, T >
|
|
{
|
|
public:
|
|
typedef T value_type;
|
|
|
|
// if BOOST_ENDIAN_FORCE_PODNESS is defined && C++0x POD's are not
|
|
// available then these two constructors will not be present
|
|
<a href="#endian">endian</a>() = default; // = default replaced by {} on C++03
|
|
explicit <a href="#explicit-endian">endian</a>(T v);
|
|
|
|
endian & <a href="#operator-eq">operator=</a>(T v);
|
|
<a href="#operator-T">operator T</a>() const;
|
|
const char* <a href="#data">data</a>() const;
|
|
};
|
|
|
|
// unaligned big endian signed integer types
|
|
typedef endian< endianness::big, int_least8_t, 8 > big8_t;
|
|
typedef endian< endianness::big, int_least16_t, 16 > big16_t;
|
|
typedef endian< endianness::big, int_least32_t, 24 > big24_t;
|
|
typedef endian< endianness::big, int_least32_t, 32 > big32_t;
|
|
typedef endian< endianness::big, int_least64_t, 40 > big40_t;
|
|
typedef endian< endianness::big, int_least64_t, 48 > big48_t;
|
|
typedef endian< endianness::big, int_least64_t, 56 > big56_t;
|
|
typedef endian< endianness::big, int_least64_t, 64 > big64_t;
|
|
|
|
// unaligned big endian unsigned integer types
|
|
typedef endian< endianness::big, uint_least8_t, 8 > ubig8_t;
|
|
typedef endian< endianness::big, uint_least16_t, 16 > ubig16_t;
|
|
typedef endian< endianness::big, uint_least32_t, 24 > ubig24_t;
|
|
typedef endian< endianness::big, uint_least32_t, 32 > ubig32_t;
|
|
typedef endian< endianness::big, uint_least64_t, 40 > ubig40_t;
|
|
typedef endian< endianness::big, uint_least64_t, 48 > ubig48_t;
|
|
typedef endian< endianness::big, uint_least64_t, 56 > ubig56_t;
|
|
typedef endian< endianness::big, uint_least64_t, 64 > ubig64_t;
|
|
|
|
// unaligned little endian signed integer types
|
|
typedef endian< endianness::little, int_least8_t, 8 > little8_t;
|
|
typedef endian< endianness::little, int_least16_t, 16 > little16_t;
|
|
typedef endian< endianness::little, int_least32_t, 24 > little24_t;
|
|
typedef endian< endianness::little, int_least32_t, 32 > little32_t;
|
|
typedef endian< endianness::little, int_least64_t, 40 > little40_t;
|
|
typedef endian< endianness::little, int_least64_t, 48 > little48_t;
|
|
typedef endian< endianness::little, int_least64_t, 56 > little56_t;
|
|
typedef endian< endianness::little, int_least64_t, 64 > little64_t;
|
|
|
|
// unaligned little endian unsigned integer types
|
|
typedef endian< endianness::little, uint_least8_t, 8 > ulittle8_t;
|
|
typedef endian< endianness::little, uint_least16_t, 16 > ulittle16_t;
|
|
typedef endian< endianness::little, uint_least32_t, 24 > ulittle24_t;
|
|
typedef endian< endianness::little, uint_least32_t, 32 > ulittle32_t;
|
|
typedef endian< endianness::little, uint_least64_t, 40 > ulittle40_t;
|
|
typedef endian< endianness::little, uint_least64_t, 48 > ulittle48_t;
|
|
typedef endian< endianness::little, uint_least64_t, 56 > ulittle56_t;
|
|
typedef endian< endianness::little, uint_least64_t, 64 > ulittle64_t;
|
|
|
|
// unaligned native endian signed integer types
|
|
typedef endian< endianness::native, int_least8_t, 8 > native8_t;
|
|
typedef endian< endianness::native, int_least16_t, 16 > native16_t;
|
|
typedef endian< endianness::native, int_least32_t, 24 > native24_t;
|
|
typedef endian< endianness::native, int_least32_t, 32 > native32_t;
|
|
typedef endian< endianness::native, int_least64_t, 40 > native40_t;
|
|
typedef endian< endianness::native, int_least64_t, 48 > native48_t;
|
|
typedef endian< endianness::native, int_least64_t, 56 > native56_t;
|
|
typedef endian< endianness::native, int_least64_t, 64 > native64_t;
|
|
|
|
// unaligned native endian unsigned integer types
|
|
typedef endian< endianness::native, uint_least8_t, 8 > unative8_t;
|
|
typedef endian< endianness::native, uint_least16_t, 16 > unative16_t;
|
|
typedef endian< endianness::native, uint_least32_t, 24 > unative24_t;
|
|
typedef endian< endianness::native, uint_least32_t, 32 > unative32_t;
|
|
typedef endian< endianness::native, uint_least64_t, 40 > unative40_t;
|
|
typedef endian< endianness::native, uint_least64_t, 48 > unative48_t;
|
|
typedef endian< endianness::native, uint_least64_t, 56 > unative56_t;
|
|
typedef endian< endianness::native, uint_least64_t, 64 > unative64_t;
|
|
|
|
// These types only present if platform has exact size integers:
|
|
|
|
// aligned big endian signed integer types
|
|
typedef endian< endianness::big, int16_t, 16, alignment::aligned > aligned_big16_t;
|
|
typedef endian< endianness::big, int32_t, 32, alignment::aligned > aligned_big32_t;
|
|
typedef endian< endianness::big, int64_t, 64, alignment::aligned > aligned_big64_t;
|
|
|
|
// aligned big endian unsigned integer types
|
|
typedef endian< endianness::big, uint16_t, 16, alignment::aligned > aligned_ubig16_t;
|
|
typedef endian< endianness::big, uint32_t, 32, alignment::aligned > aligned_ubig32_t;
|
|
typedef endian< endianness::big, uint64_t, 64, alignment::aligned > aligned_ubig64_t;
|
|
|
|
// aligned little endian signed integer types
|
|
typedef endian< endianness::little, int16_t, 16, alignment::aligned > aligned_little2_t;
|
|
typedef endian< endianness::little, int32_t, 32, alignment::aligned > aligned_little4_t;
|
|
typedef endian< endianness::little, int64_t, 64, alignment::aligned > aligned_little8_t;
|
|
|
|
// aligned little endian unsigned integer types
|
|
typedef endian< endianness::little, uint16_t, 16, alignment::aligned > aligned_ulittle2_t;
|
|
typedef endian< endianness::little, uint32_t, 32, alignment::aligned > aligned_ulittle4_t;
|
|
typedef endian< endianness::little, uint64_t, 64, alignment::aligned > aligned_ulittle8_t;
|
|
|
|
|
|
// aligned native endian typedefs are not provided because
|
|
// <cstdint> types are superior for this use case
|
|
|
|
} // namespace integer
|
|
} // namespace boost</pre>
|
|
<h3><a name="Members">Members</a></h3>
|
|
<p><code><a name="endian">endian</a>() = default; // C++03: endian(){}</code></p>
|
|
<blockquote>
|
|
<p><i>Effects:</i> Constructs an object of type <code>endian<E, T, n_bits, A></code>.</p>
|
|
</blockquote>
|
|
<p><code><a name="explicit-endian">explicit endian</a>(T v);</code></p>
|
|
<blockquote>
|
|
<p><i>Effects:</i> Constructs an object of type <code>endian<E, T, n_bits, A></code>.</p>
|
|
<p><i>Postcondition:</i> <code>x == v,</code> where <code>x</code> is the
|
|
constructed object.</p>
|
|
</blockquote>
|
|
<p><code>endian & <a name="operator-eq">operator=</a>(T v);</code></p>
|
|
<blockquote>
|
|
<p><i>Postcondition:</i> <code>x == v,</code> where <code>x</code> is the
|
|
constructed object.</p>
|
|
<p><i>Returns:</i> <code>*this</code>.</p>
|
|
</blockquote>
|
|
<p><code><a name="operator-T">operator T</a>() const;</code></p>
|
|
<blockquote>
|
|
<p><i>Returns:</i> The current value stored in <code>*this</code>, converted to
|
|
<code>value_type</code>.</p>
|
|
</blockquote>
|
|
<p><code>const char* <a name="data">data</a>() const;</code></p>
|
|
<blockquote>
|
|
<p><i>Returns:</i> A pointer to the first byte of the endian binary value stored
|
|
in <code>*this</code>.</p>
|
|
</blockquote>
|
|
<h3>Other operators</h3>
|
|
<p>Other operators on endian objects are forwarded to the equivalent
|
|
operator on <code>value_type</code>.</p>
|
|
<h2><a name="FAQ">FAQ</a></h2>
|
|
<p><b>Why bother with endian types?</b> External data portability and both speed
|
|
and space efficiency. Availability
|
|
of additional binary integer sizes and alignments is important in some
|
|
applications.</p>
|
|
<p><b>Why not just use Boost.Serialization?</b> Serialization involves a
|
|
conversion for every object involved in I/O. Endian objects require no
|
|
conversion or copying. They are already in the desired format for binary I/O.
|
|
Thus they can be read or written in bulk.</p>
|
|
<p><b>Why bother with binary I/O? Why not just use C++ Standard Library stream
|
|
inserters and extractors?</b> Using binary rather than character representations
|
|
can be more space efficient, with a side benefit of faster I/O. CPU time is
|
|
minimized because conversions to and from string are eliminated.
|
|
Furthermore, binary integers are fixed size, and so fixed-size disk records
|
|
are possible, easing sorting and allowing direct access. Disadvantages, such as the inability to use
|
|
text utilities on the resulting files, limit usefulness to applications where
|
|
the
|
|
binary I/O advantages are paramount.</p>
|
|
<p><b>Do these types have any uses outside of I/O?</b> Probably not, except for
|
|
native endianness which can be used for fine grained control over size and
|
|
alignment.</p>
|
|
<p><b>Is there is a performance hit when doing arithmetic using these types?</b> Yes, for sure,
|
|
compared to arithmetic operations on native integer types. However, these types
|
|
are usually be faster, and sometimes much faster, for I/O compared to stream
|
|
inserters and extractors, or to serialization.</p>
|
|
<p><b>Are endian types POD's?</b> Yes for C++0x. No for C++03, although several
|
|
<a href="#Compilation">macros</a> are available to force PODness in all cases.</p>
|
|
<p><b>What are the implications endian types not being POD's with C++03
|
|
compilers?</b> They
|
|
can't be used in unions. Also, compilers aren't required to align or lay
|
|
out storage in portable ways, although this potential problem hasn't prevented
|
|
use of Boost.Endian with
|
|
real compilers.</p>
|
|
<p><b>Which is better, big-endian or little-endian?</b> Big-endian tends to be a
|
|
bit more of an industry standard, but little-endian may be preferred for
|
|
applications that run primarily on x86 (Intel/AMD) and other little-endian
|
|
CPU's. The <a href="http://en.wikipedia.org/wiki/Endian">Wikipedia</a> article
|
|
gives more pros and cons.</p>
|
|
<p><b>What good is <i>native </i>endianness?</b> It provides alignment and
|
|
size guarantees not available from the built-in types. It eases generic
|
|
programming.</p>
|
|
<p><b>Why bother with the aligned endian types?</b> Aligned integer operations
|
|
may be faster (20 times, in one measurement) if the endianness and alignment of
|
|
the type matches the endianness and alignment requirements of the machine. On
|
|
common CPU architectures, that optimization is only available for aligned types.
|
|
That allows I/O of maximally efficient types on an application's primary
|
|
platform, yet produces data files are portable to all platforms. The code,
|
|
however, is
|
|
likely to be more fragile and less portable than with the unaligned types.</p>
|
|
<p><b>These types are really just byte-holders. Why provide the arithmetic
|
|
operations at all?</b> Providing a full set of operations reduces program
|
|
clutter and makes code both easier to write and to read. Consider
|
|
incrementing a variable in a record. It is very convenient to write:</p>
|
|
<pre wrap> ++record.foo;</pre>
|
|
<p wrap>Rather than:</p>
|
|
<pre wrap> int temp( record.foo);
|
|
++temp;
|
|
record.foo = temp;</pre>
|
|
<p wrap><b>Why do binary stream insertion and extraction use operators <= and >=
|
|
rather than <<= and >>=?</b> <<= and >>= associate right-to-left, which is the
|
|
opposite of << and >>, so would be very confusing and error prone. <= and >=
|
|
associate left-to-right. </p>
|
|
<h2><a name="Binary-I-O-cautions">Binary I/O warnings and cautions</a></h2>
|
|
<p><font color="#FF0000"><b><i><span style="background-color: #FFFFFF">Warning:</span></i></b></font><span style="background-color: #FFFFFF"> </span> Use
|
|
only on streams opened with filemode <code>std::ios_base::binary</code>. Thus
|
|
unformatted binary I/O should not be with the standard streams (cout, cin, etc.)
|
|
since they are opened in text mode. Use on text streams may produce incorrect
|
|
results, such as insertion of unwanted characters or premature end-of-file. For
|
|
example, on Windows 0x0D would become 0x0D, 0x0A.</p>
|
|
<p><i><b><font color="#FF0000">Caution:</font><font color="#FFFF00"> </font></b>
|
|
</i>When mixing formatted (i.e. operator << or >>) and unformatted (i.e.
|
|
operator <= or >=) stream I/O, be aware that << and >> take precedence over <=
|
|
and >=. Use parentheses to force correct order of evaluation. For example:</p>
|
|
<blockquote>
|
|
<pre>my_stream << foo <= bar; // no parentheses needed
|
|
(my_stream <= foo) << bar; // parentheses required </pre>
|
|
</blockquote>
|
|
<p>As a practical matter, it may be easier and safer to never mix the character
|
|
and binary insertion or extraction operators in the same statement.</p>
|
|
<h2><a name="Example">Example</a></h2>
|
|
<p>The <a href="../example/endian_example.cpp">endian_example.cpp</a> program writes a
|
|
binary file containing four byte big-endian and little-endian integers:</p>
|
|
<blockquote>
|
|
<pre>#include <iostream>
|
|
#include <cassert>
|
|
#include <cstdio>
|
|
#include <boost/integer/endian.hpp>
|
|
|
|
using namespace boost::integer;
|
|
|
|
namespace
|
|
{
|
|
// This is an extract from a very widely used GIS file format. I have no idea
|
|
// why a designer would mix big and little endians in the same file - but
|
|
// this is a real-world format and users wishing to write low level code
|
|
// manipulating these files have to deal with the mixed endianness.
|
|
|
|
struct header
|
|
{
|
|
big32_t file_code;
|
|
big32_t file_length;
|
|
little32_t version;
|
|
little32_t shape_type;
|
|
};
|
|
|
|
const char * filename = "test.dat";
|
|
}
|
|
|
|
int main()
|
|
{
|
|
assert( sizeof( header ) == 16 ); // requirement for interoperability
|
|
|
|
header h;
|
|
|
|
h.file_code = 0x04030201;
|
|
h.file_length = sizeof( header );
|
|
h.version = -1;
|
|
h.shape_type = 0x04030201;
|
|
|
|
// Low-level I/O such as POSIX read/write or <cstdio> fread/fwrite is sometimes
|
|
// used for binary file operations when ultimate efficiency is important.
|
|
// Such I/O is often performed in some C++ wrapper class, but to drive home the
|
|
// point that endian integers are often used in fairly low-level code that
|
|
// does bulk I/O operations, <cstdio> fopen/fwrite is used for I/O in this example.
|
|
|
|
std::FILE * fi;
|
|
|
|
if ( !(fi = std::fopen( filename, "wb" )) ) // MUST BE BINARY
|
|
{
|
|
std::cout << "could not open " << filename << '\n';
|
|
return 1;
|
|
}
|
|
|
|
if ( std::fwrite( &h, sizeof( header ), 1, fi ) != 1 )
|
|
{
|
|
std::cout << "write failure for " << filename << '\n';
|
|
return 1;
|
|
}
|
|
|
|
std::fclose( fi );
|
|
|
|
std::cout << "created file " << filename << '\n';
|
|
return 0;
|
|
}</pre>
|
|
</blockquote>
|
|
<p>After compiling and executing <a href="endian_example.cpp">endian_example.cpp</a>, a hex dump of <code>test.dat</code> shows:</p>
|
|
<blockquote>
|
|
<pre>0403 0201 0000 0010 ffff ffff 0102 0304</pre>
|
|
</blockquote>
|
|
<h2><a name="Design">Design</a> considerations for Boost.Endian</h2>
|
|
<ul>
|
|
<li>Must be suitable for I/O - in other words, must be memcpyable.</li>
|
|
<li>Must provide exactly the size and internal byte ordering specified.</li>
|
|
<li>Must work correctly when the internal integer representation has more bits
|
|
that the sum of the bits in the external byte representation. Sign extension
|
|
must work correctly when the internal integer representation type has more
|
|
bits than the sum of the bits in the external bytes. For example, using
|
|
a 64-bit integer internally to represent 40-bit (5 byte) numbers must work for
|
|
both positive and negative values.</li>
|
|
<li>Must work correctly (including using the same defined external
|
|
representation) regardless of whether a compiler treats char as signed or
|
|
unsigned.</li>
|
|
<li>Unaligned types must not cause compilers to insert padding bytes.</li>
|
|
<li>The implementation should supply optimizations only in very limited
|
|
circumstances. Experience has shown that optimizations of endian
|
|
integers often become pessimizations. While this may be obvious when changing
|
|
machines or compilers, it also happens when changing compiler switches,
|
|
compiler versions, or CPU models of the same architecture.</li>
|
|
<li>It is better software engineering if the same implementation works regardless
|
|
of the CPU endianness. In other words, #ifdefs should be avoided where
|
|
possible.</li>
|
|
</ul>
|
|
<h2><a name="Experience">Experience</a></h2>
|
|
<p>Classes with similar functionality have been independently developed by
|
|
several Boost programmers and used very successful in high-value, high-use
|
|
applications for many years. These independently developed endian libraries
|
|
often evolved from C libraries that were also widely used. Endian integers have proven widely useful across a wide
|
|
range of computer architectures and applications.</p>
|
|
<h2><a name="Motivating-use-cases">Motivating use cases</a></h2>
|
|
<p>Neil Mayhew writes: "I can also provide a meaningful use-case for this
|
|
library: reading TrueType font files from disk and processing the contents. The
|
|
data format has fixed endianness (big) and has unaligned values in various
|
|
places. Using Boost.Endian simplifies and cleans the code wonderfully."</p>
|
|
<h2><a name="C++0x">C++0x</a></h2>
|
|
<p>The availability of the C++0x
|
|
<a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2346.htm">
|
|
Defaulted Functions</a> feature is detected automatically, and will be used if
|
|
present to ensure that objects of <code>class endian</code> are trivial, and
|
|
thus POD's.</p>
|
|
<h2><a name="Compilation">Compilation</a></h2>
|
|
<p>Boost.Endian is implemented entirely within headers, with no need to link to
|
|
any Boost object libraries.</p>
|
|
<p>Several macros allow user control over features:</p>
|
|
<ul>
|
|
<li>BOOST_ENDIAN_NO_CTORS causes <code>class endian</code> to have no
|
|
constructors. The intended use is for compiling user code that must be
|
|
portable between compilers regardless of C++0x
|
|
<a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2346.htm">
|
|
Defaulted Functions</a> support. Use of constructors will always fail, <br>
|
|
</li>
|
|
<li>BOOST_ENDIAN_FORCE_PODNESS causes BOOST_ENDIAN_NO_CTORS to be defined if
|
|
the compiler does not support C++0x
|
|
<a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2346.htm">
|
|
Defaulted Functions</a>. This is ensures that , and so can be used in unions.
|
|
In C++0x, <code>class endian</code> objects are POD's even though they have
|
|
constructors.</li>
|
|
</ul>
|
|
<h2><a name="Acknowledgements">Acknowledgements</a></h2>
|
|
<p>Original design developed by Darin Adler based on classes developed by Mark
|
|
Borgerding. Four original class templates combined into a single <code>endian</code>
|
|
class template by Beman Dawes, who put the library together, provided
|
|
documentation, and added the typedefs. He also added the <code>unrolled_byte_loops</code>
|
|
sign partial specialization to correctly extend the sign when cover integer size
|
|
differs from endian representation size.</p>
|
|
<p>Comments and suggestions were
|
|
received from
|
|
Benaka Moorthi,
|
|
Christopher Kohlhoff,
|
|
Cliff Green,
|
|
Gennaro Proto,
|
|
Giovanni Piero Deretta, dizzy, Jeff Flinn,
|
|
John Maddock,
|
|
Kim Barrett,
|
|
Marsh Ray,
|
|
Martin Bonner,
|
|
Matias Capeletto,
|
|
Neil Mayhew, Phil Endecott, Rene Rivera,
|
|
Roland Schwarz, Scott McMurray,
|
|
Sebastian Redl,
|
|
Tomas Puverle, Vincente Botet, and
|
|
Yuval Ronen.</p>
|
|
<hr>
|
|
<p>Last revised:
|
|
<!--webbot bot="Timestamp" s-type="EDITED" s-format="%d %B, %Y" startspan -->25 March, 2009<!--webbot bot="Timestamp" endspan i-checksum="29032" --></p>
|
|
<p>� Copyright Beman Dawes, 2006-2009</p>
|
|
<p>Distributed under the Boost Software License, Version 1.0. (See accompanying
|
|
file <a href="../../../LICENSE_1_0.txt">LICENSE_1_0.txt</a> or copy at
|
|
<a href="http://www.boost.org/LICENSE_1_0.txt">www.boost.org/ LICENSE_1_0.txt</a>)</p>
|
|
|
|
</body>
|
|
|
|
</html> |