forked from boostorg/endian
Refactor "Choosing the approach" into its own page. It was dominating the main home page, yet is really a topic for study after other material is absorbed.
This commit is contained in:
@ -27,11 +27,12 @@
|
||||
|
||||
<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>
|
||||
<td><b>
|
||||
<a href="index.html">Endian Home</a>
|
||||
<a href="conversion.html">Conversion Functions</a>
|
||||
<a href="arithmetic.html">Arithmetic Types</a>
|
||||
<a href="buffers.html">Buffer Types</a></b></td>
|
||||
<a href="buffers.html">Buffer Types</a>
|
||||
<a href="choosing_approach.html">Choosing Approach</a></b></td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
@ -681,7 +682,7 @@ differs from endian representation size. Vicente Botet and other reviewers
|
||||
suggested supporting floating point types.</p>
|
||||
<hr>
|
||||
<p>Last revised:
|
||||
<!--webbot bot="Timestamp" s-type="EDITED" s-format="%d %B, %Y" startspan -->05 December, 2014<!--webbot bot="Timestamp" endspan i-checksum="38642" --></p>
|
||||
<!--webbot bot="Timestamp" s-type="EDITED" s-format="%d %B, %Y" startspan -->02 January, 2015<!--webbot bot="Timestamp" endspan i-checksum="38888" --></p>
|
||||
<p>© Copyright Beman Dawes, 2006-2009, 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>
|
||||
|
@ -27,11 +27,12 @@
|
||||
|
||||
<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>
|
||||
<td><b>
|
||||
<a href="index.html">Endian Home</a>
|
||||
<a href="conversion.html">Conversion Functions</a>
|
||||
<a href="arithmetic.html">Arithmetic Types</a>
|
||||
<a href="buffers.html">Buffer Types</a></b></td>
|
||||
<a href="buffers.html">Buffer Types</a>
|
||||
<a href="choosing_approach.html">Choosing Approach</a></b></td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
@ -617,7 +618,7 @@ any Boost object libraries.</p>
|
||||
</ul>
|
||||
<hr>
|
||||
<p>Last revised:
|
||||
<!--webbot bot="Timestamp" s-type="EDITED" s-format="%d %B, %Y" startspan -->06 December, 2014<!--webbot bot="Timestamp" endspan i-checksum="38644" --></p>
|
||||
<!--webbot bot="Timestamp" s-type="EDITED" s-format="%d %B, %Y" startspan -->02 January, 2015<!--webbot bot="Timestamp" endspan i-checksum="38888" --></p>
|
||||
<p>© Copyright Beman Dawes, 2006-2009, 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>
|
||||
|
305
doc/choosing_approach.html
Normal file
305
doc/choosing_approach.html
Normal file
@ -0,0 +1,305 @@
|
||||
<html>
|
||||
|
||||
<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>Choosing Approach</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="http://www.boost.org/boost.png" alt="Boost logo" align="middle" border="0" width="277" height="86"></a></td>
|
||||
<td align="middle" width="1253">
|
||||
<font size="6"><b>Choosing the Approach</b></font></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.html">Endian Home</a>
|
||||
<a href="conversion.html">Conversion Functions</a>
|
||||
<a href="arithmetic.html">Arithmetic Types</a>
|
||||
<a href="buffers.html">Buffer Types</a>
|
||||
<a href="choosing_approach.html">Choosing Approach</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="#Introduction">Introduction</a><br>
|
||||
<a href="#Choosing">Choosing between conversion functions,</a><br>
|
||||
<a href="#Choosing">buffer types, and arithmetic types</a><br>
|
||||
<a href="#Characteristics">Characteristics</a><br>
|
||||
<a href="#Endianness-invariants">Endianness invariants</a><br>
|
||||
<a href="#Conversion-explicitness">Conversion explicitness</a><br>
|
||||
<a href="#Arithmetic-operations">Arithmetic operations</a><br>
|
||||
<a href="#Sizes">Sizes</a><br>
|
||||
<a href="#Alignments">Alignments</a><br>
|
||||
<a href="#Design-patterns">Design patterns</a><br>
|
||||
<a href="#As-needed">Convert only as needed (i.e. lazy)</a><br>
|
||||
<a href="#Anticipating-need">Convert in anticipation of need</a><br>
|
||||
<a href="#Convert-generally-as-needed-locally-in-anticipation">Generally
|
||||
as needed, locally in anticipation</a><br>
|
||||
<a href="#Use-cases">Use case examples</a><br>
|
||||
<a href="#Porting-endian-unaware-codebase">Porting endian unaware codebase</a><br>
|
||||
<a href="#Porting-endian-aware-codebase">Porting endian aware codebase</a><br>
|
||||
<a href="#Reliability-arithmetic-speed">Reliability and arithmetic-speed</a><br>
|
||||
<a href="#Reliability-ease-of-use">Reliability and ease-of-use</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"><boost/endian/conversion.hpp></a><br>
|
||||
<a href="../include/boost/endian/buffers.hpp"><boost/endian/buffers.hpp></a><br>
|
||||
<a href="../include/boost/endian/arithmetic.hpp"><boost/endian/arithmetic.hpp></a></td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<h2><a name="Introduction">Introduction</a></h2>
|
||||
|
||||
<p>Deciding which is the best endianness approach (conversion functions, buffer
|
||||
types, or arithmetic types) for a particular application involves complex
|
||||
engineering trade-offs. It is hard to assess those trade-offs without some
|
||||
understanding of the different interfaces, so you might want to read the
|
||||
<a href="conversion.html">conversion functions</a>, <a href="buffers.html">
|
||||
buffer types</a>, and <a href="arithmetic.html">arithmetic types</a> pages
|
||||
before diving into this page.</p>
|
||||
|
||||
<h2><a name="Choosing">Choosing</a> between conversion functions, buffer types,
|
||||
and arithmetic types</h2>
|
||||
|
||||
<p>The best approach to endianness for a particular application depends on the interaction between
|
||||
the application's needs and the characteristics of each of the three approaches.</p>
|
||||
|
||||
<p><b>Recommendation:</b> If you are new to endianness, uncertain, or don't want to invest
|
||||
the time to
|
||||
study
|
||||
engineering trade-offs, use <a href="arithmetic.html">endian arithmetic types</a>. They are safe, easy
|
||||
to use, and easy to maintain. Use the
|
||||
<a href="#Anticipating-need"> <i>
|
||||
anticipating need</i></a> design pattern locally around performance hot spots like lengthy loops,
|
||||
if needed. </p>
|
||||
|
||||
<h3><a name="Characteristics">Characteristics</a></h3>
|
||||
|
||||
<p>The characteristics that differentiate the three approaches to endianness are the endianness
|
||||
invariants, conversion explicitness, arithmetic operations, sizes available, and
|
||||
alignment requirements.</p>
|
||||
|
||||
<h4><a name="Endianness-invariants">Endianness invariants</a></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 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 easier to use and programs easier to maintain.</p>
|
||||
|
||||
</blockquote>
|
||||
|
||||
<h4><a name="Conversion-explicitness">Conversion explicitness</a></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><a name="Arithmetic-operations">Arithmetic operations</a></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><a name="Sizes">Sizes</a></h4>
|
||||
|
||||
<blockquote>
|
||||
|
||||
<p><b>Endianness conversion functions</b> only support 1, 2, 4, and 8 byte
|
||||
integers. That'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><a name="Alignments">Alignments</a></h4>
|
||||
|
||||
<blockquote>
|
||||
|
||||
<p><b>Endianness conversion functions</b> only support aligned integer and
|
||||
floating-point types. That'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>
|
||||
uint16_t a; // big endian<br>
|
||||
uint32_t b; // big endian<br>
|
||||
} __attribute__ ((packed));</code>
|
||||
</p></blockquote>
|
||||
<p>Can be replaced with portable code like this:</p>
|
||||
<blockquote>
|
||||
<p><code>struct S {<br>
|
||||
big_uint16_ut a;<br>
|
||||
big_uint32_ut b;<br>
|
||||
};</code>
|
||||
</p></blockquote>
|
||||
</blockquote>
|
||||
|
||||
</blockquote>
|
||||
|
||||
<h3><a name="Design-patterns">Design patterns</a></h3>
|
||||
|
||||
<p>Applications often traffic in endian data as records or packets containing
|
||||
multiple endian data elements. For simplicity, we will just call them records.</p>
|
||||
|
||||
<p>If desired endianness differs from native endianness, a conversion has to be
|
||||
performed. When should that conversion occur? Three design patterns have
|
||||
evolved.</p>
|
||||
|
||||
<h4><a name="As-needed">Convert only as needed</a> (i.e. lazy)</h4>
|
||||
|
||||
<p>This pattern defers conversion to the point in the code where the data
|
||||
element is actually used.</p>
|
||||
|
||||
<p>This pattern is appropriate when which endian element is actually used varies
|
||||
greatly according to record content or other circumstances</p>
|
||||
|
||||
<h4><a name="Anticipating-need">Convert in anticipation of need</a></h4>
|
||||
|
||||
<p>This pattern performs conversion to native endianness in anticipation of use,
|
||||
such as immediately after reading records. If needed, conversion to the output
|
||||
endianness is performed after all possible needs have passed, such as just
|
||||
before writing records.</p>
|
||||
|
||||
<p>One implementation of this pattern is to create a proxy record with
|
||||
endianness converted to native in a read function, and expose only that proxy to
|
||||
the rest of the implementation. If a write function, if needed, handles the
|
||||
conversion from native to the desired output endianness.</p>
|
||||
|
||||
<p>This pattern is appropriate when all endian elements in a record are
|
||||
typically used regardless of record content or other circumstances</p>
|
||||
|
||||
<h4><a name="Convert-generally-as-needed-locally-in-anticipation">Convert
|
||||
generally only as needed, but locally in anticipation of need</a></h4>
|
||||
|
||||
<p>This pattern in general defers conversion but for specific local needs does
|
||||
anticipatory conversion.</p>
|
||||
|
||||
<p>This pattern is particularly appropriate when coupled with the endian buffer
|
||||
or arithmetic types.</p>
|
||||
|
||||
<h3><a name="Use-cases">Use case examples</a></h3>
|
||||
|
||||
<h4><a name="Porting-endian-unaware-codebase">Porting endian unaware codebase</a></h4>
|
||||
|
||||
<p>An existing codebase runs on big endian systems. It does not
|
||||
currently deal with endianness. The codebase needs to be modified so it can run
|
||||
on little endian systems under various operating systems. To ease
|
||||
transition and protect value of existing files, external data will continue to
|
||||
be maintained as big endian.</p>
|
||||
|
||||
<p dir="ltr">The <a href="arithmetic.html">endian
|
||||
arithmetic approach</a> is recommended to meet these needs. A relatively small
|
||||
number of header files dealing with binary I/O layouts need to change types. For
|
||||
example,
|
||||
<code>short</code> or <code>int16_t</code> would change to <code>big_int16_t</code>. No
|
||||
changes are required for <code>.cpp</code> files.</p>
|
||||
|
||||
<h4><a name="Porting-endian-aware-codebase">Porting endian aware codebase</a></h4>
|
||||
|
||||
<p>An existing 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 dir="ltr">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><endian.h></code>
|
||||
with <code><boost/endian/conversion.hpp></code>.</p>
|
||||
|
||||
<h4><a name="Reliability-arithmetic-speed">Reliability and arithmetic-speed</a></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><a name="Reliability-ease-of-use">Reliability and ease-of-use</a></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>
|
||||
|
||||
<hr>
|
||||
<p>Last revised:
|
||||
<!--webbot bot="Timestamp" s-type="EDITED" s-format="%d %B, %Y" startspan -->02 January, 2015<!--webbot bot="Timestamp" endspan i-checksum="38888" --></p>
|
||||
<p>© Copyright Beman Dawes, 2011, 2013, 2014</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>
|
||||
|
||||
<p> </p>
|
||||
|
||||
</body>
|
||||
|
||||
</html>
|
@ -24,11 +24,12 @@
|
||||
|
||||
<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>
|
||||
<td><b>
|
||||
<a href="index.html">Endian Home</a>
|
||||
<a href="conversion.html">Conversion Functions</a>
|
||||
<a href="arithmetic.html">Arithmetic Types</a>
|
||||
<a href="buffers.html">Buffer Types</a></b></td>
|
||||
<a href="buffers.html">Buffer Types</a>
|
||||
<a href="choosing_approach.html">Choosing Approach</a></b></td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
@ -376,7 +377,7 @@ Pierre Talbot provided the <code>int8_t endian_reverse()</code> and templated
|
||||
<code>endian_reverse_inplace()</code> implementations.</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>
|
||||
<!--webbot bot="Timestamp" s-type="EDITED" s-format="%d %B, %Y" startspan -->02 January, 2015<!--webbot bot="Timestamp" endspan i-checksum="38888" --></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>
|
||||
|
||||
|
258
doc/index.html
258
doc/index.html
@ -22,16 +22,19 @@
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<table border="0" cellpadding="5" cellspacing="0" style="border-collapse: collapse" bordercolor="#111111" bgcolor="#D7EEFF" width="100%">
|
||||
<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>
|
||||
<td><b>
|
||||
<a href="index.html">Endian Home</a>
|
||||
<a href="conversion.html">Conversion Functions</a>
|
||||
<a href="arithmetic.html">Arithmetic Types</a>
|
||||
<a href="buffers.html">Buffer Types</a></b></td>
|
||||
<a href="buffers.html">Buffer Types</a>
|
||||
<a href="choosing_approach.html">Choosing Approach</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">
|
||||
@ -44,22 +47,6 @@
|
||||
<a href="#Introduction">Introduction to the Boost.Endian library</a><br>
|
||||
<a href="#Choosing">Choosing between conversion functions,</a><br>
|
||||
<a href="#Choosing">buffer types, and arithmetic types</a><br>
|
||||
<a href="#Characteristics">Characteristics</a><br>
|
||||
<a href="#Endianness-invariants">Endianness invariants</a><br>
|
||||
<a href="#Conversion-explicitness">Conversion explicitness</a><br>
|
||||
<a href="#Arithmetic-operations">Arithmetic operations</a><br>
|
||||
<a href="#Sizes">Sizes</a><br>
|
||||
<a href="#Alignments">Alignments</a><br>
|
||||
<a href="#Design-patterns">Design patterns</a><br>
|
||||
<a href="#As-needed">Convert only as needed (i.e. lazy)</a><br>
|
||||
<a href="#Anticipating-need">Convert in anticipation of need</a><br>
|
||||
<a href="#Convert-generally-as-needed-locally-in-anticipation">Generally
|
||||
as needed, locally in anticipation</a><br>
|
||||
<a href="#Use-cases">Use case examples</a><br>
|
||||
<a href="#Porting-endian-unaware-codebase">Porting endian unaware codebase</a><br>
|
||||
<a href="#Porting-endian-aware-codebase">Porting endian aware codebase</a><br>
|
||||
<a href="#Reliability-arithmetic-speed">Reliability and arithmetic-speed</a><br>
|
||||
<a href="#Reliability-ease-of-use">Reliability and ease-of-use</a><br>
|
||||
<a href="#Intrinsic">Built-in support for Intrinsics</a><br>
|
||||
<a href="#Performance">Performance</a><br>
|
||||
<a href="#Timings">Timings for Example 2</a><br>
|
||||
@ -88,7 +75,7 @@ as needed, locally in anticipation</a><br>
|
||||
<a href="#Introduction-to-endianness">endianness</a> of integers,
|
||||
floating point numbers, and user-defined types.</p>
|
||||
<ul>
|
||||
<li>Three approaches to dealing with endianness are supported. Each has a
|
||||
<li>Three approaches to endianness are supported. Each has a
|
||||
long history of successful use, and each approach has use cases where it is
|
||||
preferred over the other approaches.<br>
|
||||
</li>
|
||||
@ -111,13 +98,6 @@ floating point numbers, and user-defined types.</p>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<p> </p>
|
||||
|
||||
<p> </p>
|
||||
|
||||
<p> </p>
|
||||
<p> </p>
|
||||
|
||||
<h2><a name="Introduction-to-endianness">Introduction to endianness</a></h2>
|
||||
|
||||
<p>Consider the following code:</p>
|
||||
@ -196,223 +176,21 @@ integers. The types may be aligned.</p>
|
||||
<h2><a name="Choosing">Choosing</a> between conversion functions, buffer types,
|
||||
and arithmetic types</h2>
|
||||
|
||||
<p>The best approach to endianness for a particular application depends on the interaction between
|
||||
the application's needs and the characteristics of each of the three (conversion
|
||||
functions, buffer types, and arithmetic types) approaches.</p>
|
||||
|
||||
<p><b>Recommendation:</b> If you are new to endianness, uncertain, or don't want to invest
|
||||
the time to
|
||||
study
|
||||
engineering trade-offs, use <a href="arithmetic.html">endian arithmetic types</a>. They are safe, easy
|
||||
to use, and easy to maintain. Use the
|
||||
<a href="#Anticipating-need"> <i>
|
||||
anticipating need</i></a> design pattern locally around performance hot spots like lengthy loops,
|
||||
if needed. </p>
|
||||
|
||||
<h3><a name="Characteristics">Characteristics</a></h3>
|
||||
|
||||
<p>The characteristics that differentiate the three approaches to endianness are the endianness
|
||||
invariants, conversion explicitness, arithmetic operations, sizes available, and
|
||||
alignment requirements.</p>
|
||||
|
||||
<h4><a name="Endianness-invariants">Endianness invariants</a></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 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 easier to use and programs easier to maintain.</p>
|
||||
|
||||
</blockquote>
|
||||
|
||||
<h4><a name="Conversion-explicitness">Conversion explicitness</a></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><a name="Arithmetic-operations">Arithmetic operations</a></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><a name="Sizes">Sizes</a></h4>
|
||||
|
||||
<blockquote>
|
||||
|
||||
<p><b>Endianness conversion functions</b> only support 1, 2, 4, and 8 byte
|
||||
integers. That'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><a name="Alignments">Alignments</a></h4>
|
||||
|
||||
<blockquote>
|
||||
|
||||
<p><b>Endianness conversion functions</b> only support aligned integer and
|
||||
floating-point types. That'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>
|
||||
uint16_t a; // big endian<br>
|
||||
uint32_t b; // big endian<br>
|
||||
} __attribute__ ((packed));</code>
|
||||
</p></blockquote>
|
||||
<p>Can be replaced with portable code like this:</p>
|
||||
<blockquote>
|
||||
<p><code>struct S {<br>
|
||||
big_uint16_ut a;<br>
|
||||
big_uint32_ut b;<br>
|
||||
};</code>
|
||||
</p></blockquote>
|
||||
</blockquote>
|
||||
|
||||
</blockquote>
|
||||
|
||||
<h3><a name="Design-patterns">Design patterns</a></h3>
|
||||
|
||||
<p>Applications often traffic in endian data as records or packets containing
|
||||
multiple endian data elements. For simplicity, we will just call them records.</p>
|
||||
|
||||
<p>If desired endianness differs from native endianness, a conversion has to be
|
||||
performed. When should that conversion occur? Three design patterns have
|
||||
evolved.</p>
|
||||
|
||||
<h4><a name="As-needed">Convert only as needed</a> (i.e. lazy)</h4>
|
||||
|
||||
<p>This pattern defers conversion to the point in the code where the data
|
||||
element is actually used.</p>
|
||||
|
||||
<p>This pattern is appropriate when which endian element is actually used varies
|
||||
greatly according to record content or other circumstances</p>
|
||||
|
||||
<h4><a name="Anticipating-need">Convert in anticipation of need</a></h4>
|
||||
|
||||
<p>This pattern performs conversion to native endianness in anticipation of use,
|
||||
such as immediately after reading records. If needed, conversion to the output
|
||||
endianness is performed after all possible needs have passed, such as just
|
||||
before writing records.</p>
|
||||
|
||||
<p>One implementation of this pattern is to create a proxy record with
|
||||
endianness converted to native in a read function, and expose only that proxy to
|
||||
the rest of the implementation. If a write function, if needed, handles the
|
||||
conversion from native to the desired output endianness.</p>
|
||||
|
||||
<p>This pattern is appropriate when all endian elements in a record are
|
||||
typically used regardless of record content or other circumstances</p>
|
||||
|
||||
<h4><a name="Convert-generally-as-needed-locally-in-anticipation">Convert
|
||||
generally only as needed, but locally in anticipation of need</a></h4>
|
||||
|
||||
<p>This pattern in general defers conversion but for specific local needs does
|
||||
anticipatory conversion.</p>
|
||||
|
||||
<p>This pattern is particularly appropriate when coupled with the endian buffer
|
||||
or arithmetic types.</p>
|
||||
|
||||
<h3><a name="Use-cases">Use case examples</a></h3>
|
||||
|
||||
<h4><a name="Porting-endian-unaware-codebase">Porting endian unaware codebase</a></h4>
|
||||
|
||||
<p>An existing codebase runs on big endian systems. It does not
|
||||
currently deal with endianness. The codebase needs to be modified so it can run
|
||||
on little endian systems under various operating systems. To ease
|
||||
transition and protect value of existing files, external data will continue to
|
||||
be maintained as big endian.</p>
|
||||
|
||||
<p dir="ltr">The <a href="arithmetic.html">endian
|
||||
arithmetic approach</a> is recommended to meet these needs. A relatively small
|
||||
number of header files dealing with binary I/O layouts need to change types. For
|
||||
example,
|
||||
<code>short</code> or <code>int16_t</code> would change to <code>big_int16_t</code>. No
|
||||
changes are required for <code>.cpp</code> files.</p>
|
||||
|
||||
<h4><a name="Porting-endian-aware-codebase">Porting endian aware codebase</a></h4>
|
||||
|
||||
<p>An existing 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 dir="ltr">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><endian.h></code>
|
||||
with <code><boost/endian/conversion.hpp></code>.</p>
|
||||
|
||||
<h4><a name="Reliability-arithmetic-speed">Reliability and arithmetic-speed</a></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><a name="Reliability-ease-of-use">Reliability and ease-of-use</a></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>
|
||||
<p>This section has been moved to its own <a href="choosing_approach.html">
|
||||
Choosing the Approach</a> page. </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
|
||||
<p>Most compilers, including GCC, Clang, and Visual C++, supply built-in support for byte swapping intrinsics.
|
||||
The Endian 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
|
||||
<p>Defining the macro <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>
|
||||
<code>byteswap.h </code>are not being found by your compiler, perhaps because it
|
||||
is an older release or has very limited supporting libraries.</p>
|
||||
<p>The macro <code>BOOST_ENDIAN_INTRINSIC_MSG</code> is defined as
|
||||
either <code>"no byte swap intrinsics"</code> or a string describing the
|
||||
particular set of intrinsics being used.</p>
|
||||
particular set of intrinsics being used. Useful for eliminating missing
|
||||
intrinsics as a source of performance issues.</p>
|
||||
|
||||
<h2><a name="Performance">Performance</a></h2>
|
||||
|
||||
@ -762,7 +540,7 @@ stores, multiple instructions are required on common platforms.</p>
|
||||
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>
|
||||
memory space is a minor secondary use.</p>
|
||||
</blockquote>
|
||||
<p><b>Why bother with binary I/O? Why not just use C++ Standard Library stream
|
||||
inserters and extractors?</b></p>
|
||||
@ -876,7 +654,7 @@ 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 -->31 December, 2014<!--webbot bot="Timestamp" endspan i-checksum="38637" --></p>
|
||||
<!--webbot bot="Timestamp" s-type="EDITED" s-format="%d %B, %Y" startspan -->02 January, 2015<!--webbot bot="Timestamp" endspan i-checksum="38888" --></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>
|
||||
|
Reference in New Issue
Block a user