Files
boost_endian/doc/index.html
T
2014-12-16 11:45:22 -05:00

798 lines
35 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<html xmlns:v="urn:schemas-microsoft-com:vml" xmlns:o="urn:schemas-microsoft-com:office:office" xmlns="http://www.w3.org/TR/REC-html40">
<head>
<meta name="GENERATOR" content="Microsoft FrontPage 5.0">
<meta name="ProgId" content="FrontPage.Editor.Document">
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<title>Endian Library</title>
<link href="styles.css" rel="stylesheet">
</head>
<body>
<table border="0" cellpadding="5" cellspacing="0" style="border-collapse: collapse" bordercolor="#111111" width="100%">
<tr>
<td width="339">
<a href="../../../index.html">
<img src="../../../boost.png" alt="boost.png (6897 bytes)" align="middle" border="0" width="277" height="86"></a></td>
<td align="middle" width="1253">
<b>
<font size="6">Endian Library</font></b></td>
</tr>
</table>
<table border="0" cellpadding="5" cellspacing="0" style="border-collapse: collapse" bordercolor="#111111" bgcolor="#D7EEFF" width="100%">
<tr>
<td><b><a href="../../../index.htm">Boost Home</a>&nbsp;&nbsp;&nbsp;&nbsp;
<a href="index.html">Endian Home</a>&nbsp;&nbsp;&nbsp;&nbsp;
<a href="conversion.html">Conversion Functions</a>&nbsp;&nbsp;&nbsp;&nbsp;
<a href="arithmetic.html">Arithmetic Types</a>&nbsp;&nbsp;&nbsp;&nbsp;
<a href="buffers.html">Buffer Types</a></b></td>
</tr>
</table>
<p></p>
<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="#Abstract">Abstract</a><br>
<a href="#Introduction-to-endianness">Introduction to endianness</a><br>
<a href="#Introduction">Introduction to the Boost.Endian library</a><br>
<a href="#Choosing">Choosing approaches</a><br>
<a href="#Intrinsic">Built-in support for Intrinsics</a><br>
<a href="#Performance">Performance</a><br>
&nbsp;&nbsp;&nbsp; <a href="#Timings">Timings</a><br>
&nbsp;&nbsp;&nbsp; <a href="#Conclusions">Conclusions</a><br>
<a href="#FAQ">FAQ</a><br>
<a href="#Release-history">Release history</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="../include/boost/endian/conversion.hpp">&lt;boost/endian/conversion.hpp&gt;</a><br>
<a href="../include/boost/endian/buffers.hpp">&lt;boost/endian/buffers.hpp&gt;</a><br>
<a href="../include/boost/endian/arithmetic.hpp">&lt;boost/endian/arithmetic.hpp&gt;</a></td>
</tr>
</table>
<h2><a name="Abstract">Abstract</a></h2>
<p>Boost.Endian provides facilities to manipulate the
<a href="#Introduction-to-endianness">endianness</a> of integers,
floating point numbers, and user-defined types.</p>
<ul>
<li>Primary use cases:<br>
&nbsp;<ul>
<li>Data portability. The Endian library supports binary data exchange, via either external media or network transmission,
regardless of platform endianness.<br>
&nbsp;</li>
<li>Program portability. POSIX-based and
Windows-based operating systems traditionally supply libraries with
non-portable functions to perform endian conversion. There are at least four
non-compatible sets of functions in common use. The Endian library is
portable across all C++ platforms.<br>
&nbsp;</li>
</ul>
</li>
<li>Secondary use case: Minimizing storage size via sizes and/or alignments not supported by the
standard C++ arithmetic types.<br>
<br></li>
<li>Three approaches to dealing with endianness are provided. Each approach has a
long history of successful use, and each approach has use cases where it is
preferred over the other approaches.</li>
</ul>
<h2><a name="Introduction-to-endianness">Introduction to endianness</a></h2>
<p>Consider the following code:</p>
<blockquote>
<pre>int16_t i = 0x0102;
FILE * file = fopen(&quot;test.bin&quot;, &quot;wb&quot;); // binary file!
fwrite(&amp;i, sizeof(int16_t), 1, file);
fclose(file);</pre>
</blockquote>
<p>On OS X, Linux, or Windows systems with an Intel CPU, a hex dump
of the &quot;test.bin&quot; output file produces:</p>
<blockquote>
<p><code>0201</code></p>
</blockquote>
<p>On OS X systems with a PowerPC CPU, or Solaris systems with a SPARC CPU, a hex dump of the &quot;test.bin&quot;
output file produces:</p>
<blockquote>
<p><code>0102</code></p>
</blockquote>
<p>What's happening here is that Intel CPUs order the bytes of an integer with
the least-significant byte first, while SPARC CPUs place the most-significant
byte first. Some CPUs, such as the PowerPC, allow the operating system to
choose which ordering applies.</p>
<p><a name="definition"></a>Most-significant-byte-first ordering is traditionally called &quot;big endian&quot;
ordering and the least-significant-byte-first is traditionally called
&quot;little-endian&quot; ordering. The names are derived from
<a href="http://en.wikipedia.org/wiki/Jonathan_Swift" title="Jonathan Swift">
Jonathan Swift</a>'s satirical novel <i>
<a href="http://en.wikipedia.org/wiki/Gulliver's_Travels" title="Gulliver's Travels">
Gulliver’s Travels</a></i>, where rival kingdoms opened their soft-boiled eggs
at different ends.</p>
<p>See the Wikipedia's
<a href="http://en.wikipedia.org/wiki/Endianness">Endianness</a> article for an
extensive discussion of endianness.</p>
<p>Programmers can usually ignore endianness, except when reading a core
dump on little-endian systems. But programmers have to deal with endianness when exchanging binary integers and binary floating point
values between computer systems with differing endianness, whether by physical file transfer or over a network.
And programmers may also want to use the library when minimizing either internal or
external data sizes is advantageous.</p>
<h2><a name="Introduction">Introduction</a> to the Boost.Endian library</h2>
<p>The Boost.Endian library provides three different approaches to dealing with
endianness. All three approaches support integers, floating point types
except&nbsp; <code>long double</code>, and user-define types (UDTs).</p>
<p>Each approach has a long history of successful use, and each approach has use
cases where it is preferred to the other approaches.</p>
<blockquote>
<p><b><a href="conversion.html">Endian conversion functions</a> -</b> The
application uses the built-in integer and floating point types to hold values, and calls the
provided conversion functions to convert byte ordering as needed. Both mutating
and non-mutating conversions are supplied, and each comes in unconditional and
conditional variants.</p>
<p><b><a href="buffers.html">Endian buffer types</a> -</b> The application uses the provided endian
buffer types
to hold values, and explicitly converts to and from the built-in integer and
floating point types to perform arithmetic. Buffer lengths of 1 through 8 bytes
are supported, rather than just 2, 4, and 8 bytes. The types may be aligned or
unaligned.</p>
<p><b><a href="arithmetic.html">Endian arithmetic types</a> -</b> The application uses the provided endian
arithmetic types, which supply the same operations as the built-in C++
arithmetic types. All conversions are implicit. Arithmetic integer types with
lengths of 1 through 8 bytes are supported, rather than just 2, 4, and 8 byte
integers. The types may be aligned.</p>
</blockquote>
<p>Boost Endian is a header-only library.</p>
<h2><a name="Choosing">Choosing</a> between endian conversion functions, endian buffer types,
and endian arithmetic types</h2>
<p>The best approach to endianness depends on interaction between
the approach characteristics and
the application needs.</p>
<h3><a name="Approach-characteristics">Approach characteristics</a></h3>
<p>The characteristics that differentiate the approaches are the endianness
invariants, conversion explicitness, arithmetic operations, sizes available, and
alignment requirements.</p>
<h4>Endianness invariants</h4>
<blockquote>
<p><b>Endian conversion functions</b> use objects of the ordinary C++ arithmetic
types like <code>int</code> or <code>unsigned short</code> to hold values. That
breaks the implicit invariant that the C++ language rules apply. The usual
language rules only apply if the endianness of the object is currently set by
the conversion functions to the native endianness for the platform. That can
make it very hard to reason about complex logic flow, and result in difficult to
find bugs.</p>
<p><b>Endian buffer and arithmetic types</b> hold values internally as arrays of
characters with an invariant that the endianness of the array never changes.
That makes these types easy to use and programs easy to maintain.</p>
</blockquote>
<h4>Conversion explicitness</h4>
<blockquote>
<p><b>Endian conversion functions</b> and <b>buffer types</b> never perform
implicit conversions. This gives users explicit control of when conversion
occurs, and may help avoid unnecessary conversions.</p>
<p><b>Endian arithmetic types</b> perform conversion implicitly. That makes
these types very easy to use, but can result in unnecessary conversions. Failure
to hoist conversions out of inner loops can bring a performance penalty.</p>
</blockquote>
<h4>Arithmetic operations</h4>
<blockquote>
<p><b>Endian conversion functions</b> do not supply arithmetic
operations, but this is not a concern since this approach uses ordinary C++
arithmetic types to hold values.</p>
<p><b>Endian buffer types</b> do not supply arithmetic operations. Although this
approach avoids unnecessary conversions, it can result in the introduction of
additional variables and confuse maintenance programmers.</p>
<p><b>Endian</b> <b>arithmetic types</b> do supply arithmetic operations. They
are very easy to use if lots of arithmetic is involved. </p>
</blockquote>
<h4>Sizes available</h4>
<blockquote>
<p><b>Endianness conversion functions</b> only support 1, 2, 4, and 8 byte
integers. That&#39;s sufficient for many applications.</p>
<p><b>Endian buffer and arithmetic types</b> support 1, 2, 3, 4, 5, 6, 7, and 8
byte integers. For an application where memory use or I/O speed is the limiting
factor, using sizes tailored to application needs can be useful.</p>
</blockquote>
<h4>Alignments available</h4>
<blockquote>
<p><b>Endianness conversion functions</b> only support aligned integer and
floating-point types. That&#39;s sufficient for most applications.</p>
<p><b>Endian buffer and arithmetic types</b> support both aligned and unaligned
integer and floating-point types. Unaligned types are rarely needed, but when
needed they are often very useful and workarounds are painful. For example,</p>
<blockquote>
<p>Non-portable code like this:<blockquote>
<p><code>struct S {<br>
&nbsp; uint16_t a;&nbsp; // big endian<br>
&nbsp; uint32_t b;&nbsp; // big endian<br>
} __attribute__ ((packed));</code>
</p></blockquote>
<p>Can be replaced with portable code like this:</p>
<blockquote>
<p><code>struct S {<br>
&nbsp; big_uint16_ut a;<br>
&nbsp; big_uint32_ut b;<br>
};</code>
</p></blockquote>
</blockquote>
</blockquote>
<h3><a name="Use-cases">Use cases</a></h3>
<h4>Program portability use case</h4>
<p>An existing large codebase runs on little-endian Linux systems. It already
deals with endianness via
<a href="http://man7.org/linux/man-pages/man3/endian.3.html">Linux provided
functions</a>. Because of a business merger, the codebase has to be quickly
modified for Windows and possibly other operating systems, while still
supporting Linux. The codebase is reliable and the programmers are all
well-aware of endian issues. </p>
<p>These factors all argue for an <a href="conversion.html">endian conversion
approach</a> that just mechanically changes the calls to <code>htobe32</code>,
etc. to <code>boost::endian::native_to_big</code>, etc. and replaces <code>&lt;endian.h&gt;</code>
with <code>&lt;boost/endian/conversion.hpp&gt;</code>.</p>
<h4>Reliability and arithmetic-speed use case</h4>
<p>A new, complex, multi-threaded application is to be developed that must run
on little endian machines, but do big endian network I/O. The developers believe
computational speed for endian variable is critical but have seen numerous bugs
result from inability to reason about endian conversion state. They are also
worried that future maintenance changes could inadvertently introduce a lot of
slow conversions if full-blown endian arithmetic types are used.</p>
<p>The <a href="buffers.html">endian buffers</a> approach is made-to-order for
this use case.</p>
<h4>Reliability and ease-of-use use case</h4>
<p>A new, complex, multi-threaded application is to be developed that must run
on little endian machines, but do big endian network I/O. The developers believe
computational speed for endian variables is <b>not critical</b> but have seen
numerous bugs result from inability to reason about endian conversion state.
They are also concerned about ease-of-use both during development and long-term
maintenance.</p>
<p>Removing concern about conversion speed and adding concern about ease-of-use
tips the balance strongly in favor the <a href="arithmetic.html">endian
arithmetic approach</a>.</p>
<h2>Built-in support for <a name="Intrinsic">Intrinsic</a>s</h2>
<p>Supply compilers, including GCC, Clang, and Visual C++, supply built-in support for byte swapping intrinsics.
The library uses these intrinsics when available since they may result in smaller and faster generated code, particularly for release
builds.</p>
<p>Defining <code>BOOST_ENDIAN_NO_INTRINSICS</code> will suppress use
of the intrinsics. Useful when intrinsic headers such as
<code>byteswap.h </code>are not being found on your platform.</p>
<p>The macro <code>BOOST_ENDIAN_INTRINSIC_MSG</code> is defined as
either <code>&quot;no byte swap intrinsics&quot;</code> or a string describing the
particular set of intrinsics being used.</p>
<h2><a name="Performance">Performance</a></h2>
<p>Consider this problem:</p>
<table border="1" cellpadding="5" cellspacing="0" style="border-collapse: collapse" bordercolor="#111111">
<tr>
<td colspan="2">
<p align="center"><i><b><a name="Example-1">Example 1</a></b></i></td>
</tr>
<tr>
<td colspan="2"><b><i>Add 100 to a big endian value in a file, then write the
result to a file</i> </b> </td>
</tr>
<tr>
<td><i><b>Endian arithmetic type approach</b></i></td>
<td><i><b>Endian conversion function approach</b></i></td>
</tr>
<tr>
<td valign="top">
<pre>big_int32_t x;
... read into x from a file ...
x += 100;
... write x to a file ...
</pre>
</td>
<td>
<pre>
int32_t x;
... read into x from a file ...
big_to_native_inplace(x);
x += 100;
native_to_big_inplace(x);
... write x to a file ...
</pre>
</td>
</tr>
</table>
<p><b>There will be no performance difference between the two approaches in
release builds,
regardless of the native endianness of the machine.</b> That&#39;s because optimizing compilers will likely
generate exactly the same code for each. That conclusion was confirmed by
studying the generated assembly code for GCC and Visual C++. Furthermore, time
spent doing I/O will determine the speed of this application.</p>
<p>Now consider a slightly different problem:&nbsp; </p>
<table border="1" cellpadding="5" cellspacing="0" style="border-collapse: collapse" bordercolor="#111111">
<tr>
<td colspan="2">
<p align="center"><b><i><a name="Example-2">Example 2</a></i></b></td>
</tr>
<tr>
<td colspan="2"><i><b>Add a million values to a big endian value in a file, then write the
result to a file </b></i> </td>
</tr>
<tr>
<td><i><b>Endian arithmetic type approach</b></i></td>
<td><i><b>Endian conversion function approach</b></i></td>
</tr>
<tr>
<td valign="top">
<pre>big_int32_t x;
... read into x from a file ...
for (int32_t i = 0; i &lt; 1000000; ++i)
x += i;
... write x to a file ...
</pre>
</td>
<td>
<pre>int32_t x;
... read into x from a file ...
big_to_native_inplace(x);
for (int32_t i = 0; i &lt; 1000000; ++i)
x += i;
native_to_big_inplace(x);
... write x to a file ...
</pre>
</td>
</tr>
</table>
<p>With the Endian arithmetic approach, on little endian platforms an implicit conversion from and then back to
big endian is done inside the loop. With the Endian conversion function
approach, the user has ensured the conversions are done outside the loop, so the
code may run more quickly on little endian platforms.</p>
<h3><a name="Timings">Timings</a> for Example 2 (conversion functions hoisted
out of loop)</h3>
<p>These tests were run against release builds on a circa 2012 4-core little endian X64 Intel Core i5-3570K
CPU @ 3.40GHz under Windows 7.</p>
<p><b>Caveat emptor: The Windows CPU timer has very high granularity. Repeated
runs of the same tests often yield considerably different results.</b></p>
<p>See <a href="../test/loop_time_test.cpp">loop_time_test.cpp</a> and
<a href="../build/Jamfile.v2">Jamfile.v2</a> for the actual code and build
setup.
(For GCC 4.7, there are no 16-bit intrinsics, so they are emulated by using
32-bit intrinsics.)</p>
<table border="1" cellpadding="5" cellspacing="0"style="border-collapse: collapse" bordercolor="#111111">
<tr><td colspan="6" align="center"><b><font size="2">GNU C++ version 4.7.0</font></b></td></tr>
<tr><td colspan="6" align="center"><b> <font size="2">Iterations: 1000000000, Intrinsics: __builtin_bswap16, etc.</font></b></td></tr>
<tr><td><b><font size="2">Test Case</font></b></td>
<td align="center"><b><font size="2">Endian<br>arithmetic</font></b></td>
<td align="center"><b><font size="2">Endian<br>conversion<br>function</font></b></td>
</tr>
<tr><td><font size="2">16-bit aligned big endian</font></td>
<td align="right"><font size="2">1.37 s</font></td>
<td align="right"><font size="2">0.81 s</font></td></tr>
<tr><td><font size="2">16-bit aligned little endian</font></td>
<td align="right"><font size="2">0.83 s</font></td>
<td align="right"><font size="2">0.81 s</font></td></tr>
<tr><td><font size="2">16-bit unaligned big endian</font></td>
<td align="right"><font size="2">1.09 s</font></td>
<td align="right"><font size="2">0.83 s</font></td></tr>
<tr><td><font size="2">16-bit unaligned little endian</font></td>
<td align="right"><font size="2">1.09 s</font></td>
<td align="right"><font size="2">0.81 s</font></td></tr>
<tr><td><b><font size="2">32-bit aligned big endian</font></b></td>
<td align="right"><b><font size="2">0.98 s</font></b></td>
<td align="right"><b><font size="2">0.27 s</font></b></td></tr>
<tr><td><font size="2">32-bit aligned little endian</font></td>
<td align="right"><font size="2">0.28 s</font></td>
<td align="right"><font size="2">0.27 s</font></td></tr>
<tr><td><font size="2">32-bit unaligned big endian</font></td>
<td align="right"><font size="2">3.82 s</font></td>
<td align="right"><font size="2">0.27 s</font></td></tr>
<tr><td><font size="2">32-bit unaligned little endian</font></td>
<td align="right"><font size="2">3.82 s</font></td>
<td align="right"><font size="2">0.27 s</font></td></tr>
<tr><td><font size="2">64-bit aligned big endian</font></td>
<td align="right"><font size="2">1.65 s</font></td>
<td align="right"><font size="2">0.41 s</font></td></tr>
<tr><td><font size="2">64-bit aligned little endian</font></td>
<td align="right"><font size="2">0.41 s</font></td>
<td align="right"><font size="2">0.41 s</font></td></tr>
<tr><td><font size="2">64-bit unaligned big endian</font></td>
<td align="right"><font size="2">17.53 s</font></td>
<td align="right"><font size="2">0.41 s</font></td></tr>
<tr><td><font size="2">64-bit unaligned little endian</font></td>
<td align="right"><font size="2">17.52 s</font></td>
<td align="right"><font size="2">0.41 s</font></td></tr>
<tr><td colspan="6" align="center"><b> <font size="2">Iterations: 1000000000, Intrinsics: no byte swap intrinsics</font></b></td></tr>
<tr><td><b><font size="2">Test Case</font></b></td>
<td align="center"><b><font size="2">Endian<br>arithmetic</font></b></td>
<td align="center"><b><font size="2">Endian<br>conversion<br>function</font></b></td>
</tr>
<tr><td><font size="2">16-bit aligned big endian</font></td>
<td align="right"><font size="2">1.95 s</font></td>
<td align="right"><font size="2">0.81 s</font></td></tr>
<tr><td><font size="2">16-bit aligned little endian</font></td>
<td align="right"><font size="2">0.83 s</font></td>
<td align="right"><font size="2">0.81 s</font></td></tr>
<tr><td><font size="2">16-bit unaligned big endian</font></td>
<td align="right"><font size="2">1.19 s</font></td>
<td align="right"><font size="2">0.81 s</font></td></tr>
<tr><td><font size="2">16-bit unaligned little endian</font></td>
<td align="right"><font size="2">1.20 s</font></td>
<td align="right"><font size="2">0.81 s</font></td></tr>
<tr><td><b><font size="2">32-bit aligned big endian</font></b></td>
<td align="right"><b><font size="2">0.97 s</font></b></td>
<td align="right"><b><font size="2">0.28 s</font></b></td></tr>
<tr><td><font size="2">32-bit aligned little endian</font></td>
<td align="right"><font size="2">0.27 s</font></td>
<td align="right"><font size="2">0.28 s</font></td></tr>
<tr><td><font size="2">32-bit unaligned big endian</font></td>
<td align="right"><font size="2">4.10 s</font></td>
<td align="right"><font size="2">0.27 s</font></td></tr>
<tr><td><font size="2">32-bit unaligned little endian</font></td>
<td align="right"><font size="2">4.10 s</font></td>
<td align="right"><font size="2">0.27 s</font></td></tr>
<tr><td><font size="2">64-bit aligned big endian</font></td>
<td align="right"><font size="2">1.64 s</font></td>
<td align="right"><font size="2">0.42 s</font></td></tr>
<tr><td><font size="2">64-bit aligned little endian</font></td>
<td align="right"><font size="2">0.41 s</font></td>
<td align="right"><font size="2">0.41 s</font></td></tr>
<tr><td><font size="2">64-bit unaligned big endian</font></td>
<td align="right"><font size="2">17.52 s</font></td>
<td align="right"><font size="2">0.42 s</font></td></tr>
<tr><td><font size="2">64-bit unaligned little endian</font></td>
<td align="right"><font size="2">17.52 s</font></td>
<td align="right"><font size="2">0.41 s</font></td></tr>
</table>
<p><b>Comment:</b> Note that the <b><font size="2">32-bit aligned big endian </font></b>
timings are the same with or without intrinsics turned on. Presumably the
optimizer is recognizing the byte swapping and applying the intrinsics itself.</p>
<table border="1" cellpadding="5" cellspacing="0"style="border-collapse: collapse" bordercolor="#111111">
<tr><td colspan="6" align="center"><b><font size="2">Microsoft Visual C++ version 11.0</font></b></td></tr>
<tr><td colspan="6" align="center"><b> <font size="2">Iterations: 1000000000, Intrinsics: cstdlib _byteswap_ushort, etc.</font></b></td></tr>
<tr><td><b><font size="2">Test Case</font></b></td>
<td align="center"><b><font size="2">Endian<br>type</font></b></td>
<td align="center"><b><font size="2">Endian<br>conversion<br>function</font></b></td>
</tr>
<tr><td><font size="2">16-bit aligned big endian</font></td>
<td align="right"><font size="2">0.83 s</font></td>
<td align="right"><font size="2">0.51 s</font></td></tr>
<tr><td><font size="2">16-bit aligned little endian</font></td>
<td align="right"><font size="2">0.51 s</font></td>
<td align="right"><font size="2">0.50 s</font></td></tr>
<tr><td><font size="2">16-bit unaligned big endian</font></td>
<td align="right"><font size="2">1.37 s</font></td>
<td align="right"><font size="2">0.51 s</font></td></tr>
<tr><td><font size="2">16-bit unaligned little endian</font></td>
<td align="right"><font size="2">1.37 s</font></td>
<td align="right"><font size="2">0.50 s</font></td></tr>
<tr><td><b><font size="2">32-bit aligned big endian</font></b></td>
<td align="right"><b><font size="2">0.81 s</font></b></td>
<td align="right"><b><font size="2">0.50 s</font></b></td></tr>
<tr><td><font size="2">32-bit aligned little endian</font></td>
<td align="right"><font size="2">0.51 s</font></td>
<td align="right"><font size="2">0.51 s</font></td></tr>
<tr><td><font size="2">32-bit unaligned big endian</font></td>
<td align="right"><font size="2">2.98 s</font></td>
<td align="right"><font size="2">0.53 s</font></td></tr>
<tr><td><font size="2">32-bit unaligned little endian</font></td>
<td align="right"><font size="2">3.00 s</font></td>
<td align="right"><font size="2">0.51 s</font></td></tr>
<tr><td><font size="2">64-bit aligned big endian</font></td>
<td align="right"><font size="2">1.33 s</font></td>
<td align="right"><font size="2">0.33 s</font></td></tr>
<tr><td><font size="2">64-bit aligned little endian</font></td>
<td align="right"><font size="2">0.34 s</font></td>
<td align="right"><font size="2">0.27 s</font></td></tr>
<tr><td><font size="2">64-bit unaligned big endian</font></td>
<td align="right"><font size="2">7.05 s</font></td>
<td align="right"><font size="2">0.33 s</font></td></tr>
<tr><td><font size="2">64-bit unaligned little endian</font></td>
<td align="right"><font size="2">7.11 s</font></td>
<td align="right"><font size="2">0.31 s</font></td></tr>
<tr><td colspan="6" align="center"><b> <font size="2">Iterations: 1000000000, Intrinsics: no byte swap intrinsics</font></b></td></tr>
<tr><td><b><font size="2">Test Case</font></b></td>
<td align="center"><b><font size="2">Endian<br>type</font></b></td>
<td align="center"><b><font size="2">Endian<br>conversion<br>function</font></b></td>
</tr>
<tr><td><font size="2">16-bit aligned big endian</font></td>
<td align="right"><font size="2">0.83 s</font></td>
<td align="right"><font size="2">0.51 s</font></td></tr>
<tr><td><font size="2">16-bit aligned little endian</font></td>
<td align="right"><font size="2">0.51 s</font></td>
<td align="right"><font size="2">0.51 s</font></td></tr>
<tr><td><font size="2">16-bit unaligned big endian</font></td>
<td align="right"><font size="2">1.36 s</font></td>
<td align="right"><font size="2">0.51 s</font></td></tr>
<tr><td><font size="2">16-bit unaligned little endian</font></td>
<td align="right"><font size="2">1.37 s</font></td>
<td align="right"><font size="2">0.51 s</font></td></tr>
<tr><td><b><font size="2">32-bit aligned big endian</font></b></td>
<td align="right"><b><font size="2">3.42 s</font></b></td>
<td align="right"><b><font size="2">0.50 s</font></b></td></tr>
<tr><td><font size="2">32-bit aligned little endian</font></td>
<td align="right"><font size="2">0.51 s</font></td>
<td align="right"><font size="2">0.51 s</font></td></tr>
<tr><td><font size="2">32-bit unaligned big endian</font></td>
<td align="right"><font size="2">2.93 s</font></td>
<td align="right"><font size="2">0.50 s</font></td></tr>
<tr><td><font size="2">32-bit unaligned little endian</font></td>
<td align="right"><font size="2">2.95 s</font></td>
<td align="right"><font size="2">0.50 s</font></td></tr>
<tr><td><font size="2">64-bit aligned big endian</font></td>
<td align="right"><font size="2">5.99 s</font></td>
<td align="right"><font size="2">0.33 s</font></td></tr>
<tr><td><font size="2">64-bit aligned little endian</font></td>
<td align="right"><font size="2">0.33 s</font></td>
<td align="right"><font size="2">0.33 s</font></td></tr>
<tr><td><font size="2">64-bit unaligned big endian</font></td>
<td align="right"><font size="2">7.02 s</font></td>
<td align="right"><font size="2">0.27 s</font></td></tr>
<tr><td><font size="2">64-bit unaligned little endian</font></td>
<td align="right"><font size="2">7.02 s</font></td>
<td align="right"><font size="2">0.27 s</font></td></tr>
</table>
<h3><a name="Conclusions">Conclusions</a></h3>
<p>When program logic dictates many more conversions for the Endian arithmetic
approach than the Endian conversion function approach (<a href="#Example-2">example
2</a>):</p>
<blockquote>
<p><b>There may be a considerable performance difference. </b>If machine endianness differs from the
desired endianness, the Endian arithmetic approach must do the byte reversal many
times while the Endian conversion approach only does the reversal once. But if
the endianness is the same, there is no conversion with either approach and no
conversion code is generated for typical release builds.</p>
<p><b>Whether or not compiler byte swap intrinsics are explicitly available has little
impact on GCC but a lot of impact on Visual C++, for the tested compiler
versions.</b> Yet another example of why actual timing tests are needed to
determine if some coding technique has significant impact on performance.</p>
<p><b>Unaligned types are much slower that aligned types, regardless of
endianness considerations.</b> Instead of single instruction register loads and
stores, multiple instructions are required.</p>
</blockquote>
<h2>Overall <a name="FAQ">FAQ</a></h2>
<p><b>Is the implementation header only?</b></p>
<blockquote>
<p>Yes.</p>
</blockquote>
<p><b>Does the implementation use compiler intrinsic built-in byte swapping?</b></p>
<blockquote>
<p>Yes, if available. See <a href="#Intrinsic">Intrinsic built-in support</a>.</p>
</blockquote>
<p><b>Why bother with endianness?</b></p>
<blockquote>
<p>Binary data portability is the primary use case.</p>
</blockquote>
<p><b>Does endianness have any uses outside of portable binary file or network
I/O formats?</b> </p>
<blockquote>
<p>Using the unaligned integer types to save internal or external
memory space is a minor secondary use case.</p>
</blockquote>
<p><b>Why bother with binary I/O? Why not just use C++ Standard Library stream
inserters and extractors?</b></p>
<blockquote>
<p>Data interchange formats often specify binary arithmetic data.</p>
<p>Binary arithmetic data is smaller and therefore I/O is faster and file sizes
are smaller. Transfer between systems is less expensive.</p>
<p>Furthermore, binary arithmetic data is of fixed size, and so fixed-size disk
records are possible without padding, 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>
</blockquote>
<p><b>Which is better, big-endian or little-endian?</b></p>
<blockquote>
<p>Big-endian tends to be preferred in a networking environment and is a bit
more of an industry standard, but little-endian may be preferred for
applications that run primarily on x86, x64, and other little-endian
CPU's. The <a href="http://en.wikipedia.org/wiki/Endian">Wikipedia</a> article
gives more pros and cons.</p>
</blockquote>
<p><b>Why are only big, little, and native endianness supported?</b></p>
<blockquote>
<p>These are the only endian schemes that have any practical value today. PDP-11
and the other middle endian approaches are interesting historical curiosities
but have no relevance to today&#39;s C++ developers.</p>
</blockquote>
<p><b>What are the limitations of floating point support?</b></p>
<blockquote>
<p>The only supported types are four-byte <code>float</code> and eight-byte
<code>double</code>. Even after endianness has been accounted for, floating
point values will not be portable between systems that use different floating
point formats. Systems where integer endianness differs from floating point
endianness are not supported.</p>
</blockquote>
<p><b>What are the limitations of integer support?</b></p>
<blockquote>
<p>Tests have only been
performed on machines that use two's complement arithmetic. The Endian
conversion functions support 16, 32, and 64-bit aligned integers only. The
Endian types support 8, 16, 24, 32, 40, 48, 56, and 64-bit unaligned integers
and 16, 32, and 64-bit aligned integers.</p>
</blockquote>
<h2><a name="Release-history">Release history</a></h2>
<h3>Changes since formal review</h3>
<ul>
<li>
<p>The endian types have been decomposed into endian buffer types
and endian arithmetic types, as requested. The arithmetic types derive from
the buffer types.</li>
<li>
<p>Headers have been renamed to <code>endian/arithmetic.hpp</code> and
<code>endian/conversion.hpp</code>. <code>endian/buffers.hpp</code> has been
added.
Infrastructure file names were changed accordingly.</li>
<li>
<p>The endian buffer and arithmetic types and endian conversion functions now support 32-bit (<code>float)</code> and
64-bit <code>(double)</code> floating point, as requested.</li>
<li>The endian types now have stream inserter and extractor templates, as
requested.</li>
<li>Both the endian types and endian conversion functions now support UDTs, as requested.</li>
<li>The endian type aliases have been renamed,
using a naming pattern that is consistent for both integer and floating point, .</li>
<li>The conversion functions have been much revised,
refactored, and otherwise improved based on review comments.<ul>
<li>Functions have been renamed to clarify their functionality.</li>
<li>Both return-by-value and modify-in-place interfaces are provided, as
requested.</li>
<li>In addition to the named-endianness functions, functions that perform
compile-time (via template) and run-time (via function argument) dispatch
are now provided, as requested.</li>
</ul>
</li>
<li>Compiler (Clang, GCC, VisualC++, etc.) intrinsics and built-in functions
are used in the implementation where appropriate, as requested.</li>
<li>For the endian types, the implementation uses the endian conversion functions,
and thus the intrinsics,
as requested.</li>
<li><code>order::native</code> is now a synonym for <code>order::big</code>
or <code>order::little</code> according to the endianness of the platform, as
requested. This reduces the number of template specializations required.</li>
<li><code>endian_reverse()</code> overloads for <code>int8_t</code> and <code>
uint8_t</code> have been added for improved generality. (Pierre Talbot)</li>
<li>Overloads of <code>endian_reverse_inplace()</code> have been replaced with a single <code>
endian_reverse_inplace()</code> template. (Pierre Talbot)</li>
<li>C++11 features such as <code>noexcept</code> are now used, while still
supporting C++03 compilers.</li>
<li>Headers have been reorganized to make them easier to read,
with a synopsis at the front and implementation following, as requested.</li>
<li>Documentation has been revised to address most, but not all, concerns
raised during formal review.</li>
<li>Acknowledgements have been updated.</li>
</ul>
<h2><a name="Acknowledgements">Acknowledgements</a></h2>
<p>Comments and suggestions were received from Adder, Benaka Moorthi,
Christopher Kohlhoff, Cliff Green, Daniel James, Gennaro Proto, Giovanni Piero
Deretta, Gordon Woodhull, dizzy, Hartmut Kaiser, Jeff Flinn, John Filo, John
Maddock, Kim Barrett, Marsh Ray, Martin Bonner, Mathias Gaunard, Matias
Capeletto, Neil Mayhew, Paul Bristow, Pierre Talbot, Phil Endecott, Pyry Jahkola,
Rene Rivera, Robert Stewart, Roland Schwarz, Scott McMurray, Sebastian Redl, Tim
Blechmann, Tim Moore, tymofey, Tomas Puverle, Vincente Botet, Yuval Ronen and
Vitaly Budovski,.</p>
<hr>
<p>Last revised:
<!--webbot bot="Timestamp" s-type="EDITED" s-format="%d %B, %Y" startspan -->16 December, 2014<!--webbot bot="Timestamp" endspan i-checksum="38645" --></p>
<p>© Copyright Beman Dawes, 2011, 2013</p>
<p>Distributed under the Boost Software License, Version 1.0. See
<a href="http://www.boost.org/LICENSE_1_0.txt">www.boost.org/ LICENSE_1_0.txt</a></p>
</body>
</html>