2 Copyright 2011-2016 Beman Dawes
4 Distributed under the Boost Software License, Version 1.0.
5 (http://www.boost.org/LICENSE_1_0.txt)
14 The internal byte order of arithmetic types is traditionally called
15 *endianness*. See the http://en.wikipedia.org/wiki/Endian[Wikipedia] for a full
16 exploration of *endianness*, including definitions of *big endian* and *little
19 Header `boost/endian/buffers.hpp` provides `endian_buffer`, a portable endian
20 integer binary buffer class template with control over byte order, value type,
21 size, and alignment independent of the platform's native endianness. Typedefs
22 provide easy-to-use names for common configurations.
24 Use cases primarily involve data portability, either via files or network
25 connections, but these byte-holders may also be used to reduce memory use, file
26 size, or network activity since they provide binary numeric sizes not otherwise
29 Class `endian_buffer` is aimed at users who wish explicit control over when
30 endianness conversions occur. It also serves as the base class for the
31 <<arithmetic,endian_arithmetic>> class template, which is aimed at users who
32 wish fully automatic endianness conversion and direct support for all normal
33 arithmetic operations.
37 The `example/endian_example.cpp` program writes a binary file containing
38 four-byte, big-endian and little-endian integers:
43 #include <boost/endian/buffers.hpp> // see Synopsis below
44 #include <boost/static_assert.hpp>
46 using namespace boost::endian;
50 // This is an extract from a very widely used GIS file format.
51 // Why the designer decided to mix big and little endians in
52 // the same file is not known. But this is a real-world format
53 // and users wishing to write low level code manipulating these
54 // files have to deal with the mixed endianness.
58 big_int32_buf_t file_code;
59 big_int32_buf_t file_length;
60 little_int32_buf_t version;
61 little_int32_buf_t shape_type;
64 const char* filename = "test.dat";
67 int main(int, char* [])
71 BOOST_STATIC_ASSERT(sizeof(h) == 16U); // reality check
73 h.file_code = 0x01020304;
74 h.file_length = sizeof(header);
76 h.shape_type = 0x01020304;
78 // Low-level I/O such as POSIX read/write or <cstdio>
79 // fread/fwrite is sometimes used for binary file operations
80 // when ultimate efficiency is important. Such I/O is often
81 // performed in some C++ wrapper class, but to drive home the
82 // point that endian integers are often used in fairly
83 // low-level code that does bulk I/O operations, <cstdio>
84 // fopen/fwrite is used for I/O in this example.
86 std::FILE* fi = std::fopen(filename, "wb"); // MUST BE BINARY
90 std::cout << "could not open " << filename << '\n';
94 if (std::fwrite(&h, sizeof(header), 1, fi) != 1)
96 std::cout << "write failure for " << filename << '\n';
102 std::cout << "created file " << filename << '\n';
108 After compiling and executing `example/endian_example.cpp`, a hex dump of
112 01020304 00000010 01000000 04030201
115 Notice that the first two 32-bit integers are big endian while the second two
116 are little endian, even though the machine this was compiled and run on was
121 Requires `<climits>`, `CHAR_BIT == 8`. If `CHAR_BIT` is some other value,
122 compilation will result in an `#error`. This restriction is in place because the
123 design, implementation, testing, and documentation has only considered issues
124 related to 8-bit bytes, and there have been no real-world use cases presented
127 In {cpp}03, `endian_buffer` does not meet the requirements for POD types because
128 it has constructors and a private data member. This means that
129 common use cases are relying on unspecified behavior in that the {cpp} Standard
130 does not guarantee memory layout for non-POD types. This has not been a problem
131 in practice since all known {cpp} compilers lay out memory as if `endian` were
132 a POD type. In {cpp}11, it is possible to specify the default constructor as
133 trivial, and private data members and base classes no longer disqualify a type
134 from being a POD type. Thus under {cpp}11, `endian_buffer` will no longer be
135 relying on unspecified behavior.
139 * Big endian| little endian | native endian byte ordering.
141 * Unaligned | aligned
142 * 1-8 byte (unaligned) | 1, 2, 4, 8 byte (aligned)
143 * Choice of value type
145 ## Enums and typedefs
147 Two scoped enums are provided:
150 enum class order { big, little, native };
152 enum class align { no, yes };
155 One class template is provided:
158 template <order Order, typename T, std::size_t Nbits,
159 align Align = align::no>
163 Typedefs, such as `big_int32_buf_t`, provide convenient naming conventions for
168 |Name |Alignment |Endianness |Sign |Sizes in bits (n)
169 |`big_intN_buf_t` |no |big |signed |8,16,24,32,40,48,56,64
170 |`big_uintN_buf_t` |no |big |unsigned |8,16,24,32,40,48,56,64
171 |`little_intN_buf_t` |no |little |signed |8,16,24,32,40,48,56,64
172 |`little_uintN_buf_t` |no |little |unsigned |8,16,24,32,40,48,56,64
173 |`native_intN_buf_t` |no |native |signed |8,16,24,32,40,48,56,64
174 |`native_uintN_buf_t` |no |native |unsigned |8,16,24,32,40,48,56,64
175 |`big_intN_buf_at` |yes |big |signed |8,16,32,64
176 |`big_uintN_buf_at` |yes |big |unsigned |8,16,32,64
177 |`little_intN_buf_at` |yes |little |signed |8,16,32,64
178 |`little_uintN_buf_at` |yes |little |unsigned |8,16,32,64
181 The unaligned types do not cause compilers to insert padding bytes in classes
182 and structs. This is an important characteristic that can be exploited to
183 minimize wasted space in memory, files, and network transmissions.
185 CAUTION: Code that uses aligned types is possibly non-portable because alignment
186 requirements vary between hardware architectures and because alignment may be
187 affected by compiler switches or pragmas. For example, alignment of an 64-bit
188 integer may be to a 32-bit boundary on a 32-bit machine and to a 64-bit boundary
189 on a 64-bit machine. Furthermore, aligned types are only available on
190 architectures with 8, 16, 32, and 64-bit integer types.
192 TIP: Prefer unaligned buffer types.
194 TIP: Protect yourself against alignment ills. For example:
199 static_assert(sizeof(containing_struct) == 12, "sizeof(containing_struct) is wrong");
202 Note: One-byte big and little buffer types have identical layout on all
203 platforms, so they never actually reverse endianness. They are provided to
204 enable generic code, and to improve code readability and searchability.
206 ## Class template `endian_buffer`
208 An `endian_buffer` is a byte-holder for arithmetic types with
209 user-specified endianness, value type, size, and alignment.
218 // C++11 features emulated if not available
220 enum class align { no, yes };
222 template <order Order, class T, std::size_t Nbits,
223 align Align = align::no>
228 typedef T value_type;
230 endian_buffer() noexcept = default;
231 explicit endian_buffer(T v) noexcept;
233 endian_buffer& operator=(T v) noexcept;
234 value_type value() const noexcept;
235 unsigned char* data() noexcept;
236 unsigned char const* data() const noexcept;
240 unsigned char value_[Nbits / CHAR_BIT]; // exposition only
244 template <class charT, class traits, order Order, class T,
245 std::size_t n_bits, align Align>
246 std::basic_ostream<charT, traits>&
247 operator<<(std::basic_ostream<charT, traits>& os,
248 const endian_buffer<Order, T, n_bits, Align>& x);
251 template <class charT, class traits, order Order, class T,
252 std::size_t n_bits, align A>
253 std::basic_istream<charT, traits>&
254 operator>>(std::basic_istream<charT, traits>& is,
255 endian_buffer<Order, T, n_bits, Align>& x);
259 // unaligned big endian signed integer buffers
260 typedef endian_buffer<order::big, int_least8_t, 8> big_int8_buf_t;
261 typedef endian_buffer<order::big, int_least16_t, 16> big_int16_buf_t;
262 typedef endian_buffer<order::big, int_least32_t, 24> big_int24_buf_t;
263 typedef endian_buffer<order::big, int_least32_t, 32> big_int32_buf_t;
264 typedef endian_buffer<order::big, int_least64_t, 40> big_int40_buf_t;
265 typedef endian_buffer<order::big, int_least64_t, 48> big_int48_buf_t;
266 typedef endian_buffer<order::big, int_least64_t, 56> big_int56_buf_t;
267 typedef endian_buffer<order::big, int_least64_t, 64> big_int64_buf_t;
269 // unaligned big endian unsigned integer buffers
270 typedef endian_buffer<order::big, uint_least8_t, 8> big_uint8_buf_t;
271 typedef endian_buffer<order::big, uint_least16_t, 16> big_uint16_buf_t;
272 typedef endian_buffer<order::big, uint_least32_t, 24> big_uint24_buf_t;
273 typedef endian_buffer<order::big, uint_least32_t, 32> big_uint32_buf_t;
274 typedef endian_buffer<order::big, uint_least64_t, 40> big_uint40_buf_t;
275 typedef endian_buffer<order::big, uint_least64_t, 48> big_uint48_buf_t;
276 typedef endian_buffer<order::big, uint_least64_t, 56> big_uint56_buf_t;
277 typedef endian_buffer<order::big, uint_least64_t, 64> big_uint64_buf_t;
279 // unaligned big endian floating point buffers
280 typedef endian_buffer<order::big, float, 32> big_float32_buf_t;
281 typedef endian_buffer<order::big, double, 64> big_float64_buf_t;
283 // unaligned little endian signed integer buffers
284 typedef endian_buffer<order::little, int_least8_t, 8> little_int8_buf_t;
285 typedef endian_buffer<order::little, int_least16_t, 16> little_int16_buf_t;
286 typedef endian_buffer<order::little, int_least32_t, 24> little_int24_buf_t;
287 typedef endian_buffer<order::little, int_least32_t, 32> little_int32_buf_t;
288 typedef endian_buffer<order::little, int_least64_t, 40> little_int40_buf_t;
289 typedef endian_buffer<order::little, int_least64_t, 48> little_int48_buf_t;
290 typedef endian_buffer<order::little, int_least64_t, 56> little_int56_buf_t;
291 typedef endian_buffer<order::little, int_least64_t, 64> little_int64_buf_t;
293 // unaligned little endian unsigned integer buffers
294 typedef endian_buffer<order::little, uint_least8_t, 8> little_uint8_buf_t;
295 typedef endian_buffer<order::little, uint_least16_t, 16> little_uint16_buf_t;
296 typedef endian_buffer<order::little, uint_least32_t, 24> little_uint24_buf_t;
297 typedef endian_buffer<order::little, uint_least32_t, 32> little_uint32_buf_t;
298 typedef endian_buffer<order::little, uint_least64_t, 40> little_uint40_buf_t;
299 typedef endian_buffer<order::little, uint_least64_t, 48> little_uint48_buf_t;
300 typedef endian_buffer<order::little, uint_least64_t, 56> little_uint56_buf_t;
301 typedef endian_buffer<order::little, uint_least64_t, 64> little_uint64_buf_t;
303 // unaligned little endian floating point buffers
304 typedef endian_buffer<order::little, float, 32> little_float32_buf_t;
305 typedef endian_buffer<order::little, double, 64> little_float64_buf_t;
307 // unaligned native endian signed integer types
308 typedef implementation-defined_int8_buf_t native_int8_buf_t;
309 typedef implementation-defined_int16_buf_t native_int16_buf_t;
310 typedef implementation-defined_int24_buf_t native_int24_buf_t;
311 typedef implementation-defined_int32_buf_t native_int32_buf_t;
312 typedef implementation-defined_int40_buf_t native_int40_buf_t;
313 typedef implementation-defined_int48_buf_t native_int48_buf_t;
314 typedef implementation-defined_int56_buf_t native_int56_buf_t;
315 typedef implementation-defined_int64_buf_t native_int64_buf_t;
317 // unaligned native endian unsigned integer types
318 typedef implementation-defined_uint8_buf_t native_uint8_buf_t;
319 typedef implementation-defined_uint16_buf_t native_uint16_buf_t;
320 typedef implementation-defined_uint24_buf_t native_uint24_buf_t;
321 typedef implementation-defined_uint32_buf_t native_uint32_buf_t;
322 typedef implementation-defined_uint40_buf_t native_uint40_buf_t;
323 typedef implementation-defined_uint48_buf_t native_uint48_buf_t;
324 typedef implementation-defined_uint56_buf_t native_uint56_buf_t;
325 typedef implementation-defined_uint64_buf_t native_uint64_buf_t;
327 // unaligned native endian floating point types
328 typedef implementation-defined_float32_buf_t native_float32_buf_t;
329 typedef implementation-defined_float64_buf_t native_float64_buf_t;
331 // aligned big endian signed integer buffers
332 typedef endian_buffer<order::big, int8_t, 8, align::yes> big_int8_buf_at;
333 typedef endian_buffer<order::big, int16_t, 16, align::yes> big_int16_buf_at;
334 typedef endian_buffer<order::big, int32_t, 32, align::yes> big_int32_buf_at;
335 typedef endian_buffer<order::big, int64_t, 64, align::yes> big_int64_buf_at;
337 // aligned big endian unsigned integer buffers
338 typedef endian_buffer<order::big, uint8_t, 8, align::yes> big_uint8_buf_at;
339 typedef endian_buffer<order::big, uint16_t, 16, align::yes> big_uint16_buf_at;
340 typedef endian_buffer<order::big, uint32_t, 32, align::yes> big_uint32_buf_at;
341 typedef endian_buffer<order::big, uint64_t, 64, align::yes> big_uint64_buf_at;
343 // aligned big endian floating point buffers
344 typedef endian_buffer<order::big, float, 32, align::yes> big_float32_buf_at;
345 typedef endian_buffer<order::big, double, 64, align::yes> big_float64_buf_at;
347 // aligned little endian signed integer buffers
348 typedef endian_buffer<order::little, int8_t, 8, align::yes> little_int8_buf_at;
349 typedef endian_buffer<order::little, int16_t, 16, align::yes> little_int16_buf_at;
350 typedef endian_buffer<order::little, int32_t, 32, align::yes> little_int32_buf_at;
351 typedef endian_buffer<order::little, int64_t, 64, align::yes> little_int64_buf_at;
353 // aligned little endian unsigned integer buffers
354 typedef endian_buffer<order::little, uint8_t, 8, align::yes> little_uint8_buf_at;
355 typedef endian_buffer<order::little, uint16_t, 16, align::yes> little_uint16_buf_at;
356 typedef endian_buffer<order::little, uint32_t, 32, align::yes> little_uint32_buf_at;
357 typedef endian_buffer<order::little, uint64_t, 64, align::yes> little_uint64_buf_at;
359 // aligned little endian floating point buffers
360 typedef endian_buffer<order::little, float, 32, align::yes> little_float32_buf_at;
361 typedef endian_buffer<order::little, double, 64, align::yes> little_float64_buf_at;
363 // aligned native endian typedefs are not provided because
364 // <cstdint> types are superior for this use case
366 } // namespace endian
370 The `implementation-defined` text in typedefs above is either `big` or `little`
371 according to the native endianness of the platform.
373 The expository data member `value_` stores the current value of the
374 `endian_buffer` object as a sequence of bytes ordered as specified by the
375 `Order` template parameter. The `CHAR_BIT` macro is defined in `<climits>`.
376 The only supported value of `CHAR_BIT` is 8.
378 The valid values of `Nbits` are as follows:
380 * When `sizeof(T)` is 1, `Nbits` shall be 8;
381 * When `sizeof(T)` is 2, `Nbits` shall be 16;
382 * When `sizeof(T)` is 4, `Nbits` shall be 24 or 32;
383 * When `sizeof(T)` is 8, `Nbits` shall be 40, 48, 56, or 64.
385 Other values of `sizeof(T)` are not supported.
387 When `Nbits` is equal to `sizeof(T)*8`, `T` must be a trivially copyable type
388 (such as `float`) that is assumed to have the same endianness as `uintNbits_t`.
390 When `Nbits` is less than `sizeof(T)*8`, `T` must be either a standard integral
391 type ({cpp}std, [basic.fundamental]) or an `enum`.
396 endian_buffer() noexcept = default;
401 Effects:: Constructs an uninitialized object.
404 explicit endian_buffer(T v) noexcept;
409 Effects:: `endian_store<T, Nbits/8, Order>( value_, v )`.
412 endian_buffer& operator=(T v) noexcept;
417 Effects:: `endian_store<T, Nbits/8, Order>( value_, v )`.
421 value_type value() const noexcept;
426 Returns:: `endian_load<T, Nbits/8, Order>( value_ )`.
429 unsigned char* data() noexcept;
432 unsigned char const* data() const noexcept;
438 A pointer to the first byte of `value_`.
440 ### Non-member functions
443 template <class charT, class traits, order Order, class T,
444 std::size_t n_bits, align Align>
445 std::basic_ostream<charT, traits>& operator<<(std::basic_ostream<charT, traits>& os,
446 const endian_buffer<Order, T, n_bits, Align>& x);
451 Returns:: `os << x.value()`.
454 template <class charT, class traits, order Order, class T,
455 std::size_t n_bits, align A>
456 std::basic_istream<charT, traits>& operator>>(std::basic_istream<charT, traits>& is,
457 endian_buffer<Order, T, n_bits, Align>& x);
473 See the <<overview_faq,Overview FAQ>> for a library-wide FAQ.
475 Why not just use Boost.Serialization?::
476 Serialization involves a conversion for every object involved in I/O. Endian
477 integers require no conversion or copying. They are already in the desired
478 format for binary I/O. Thus they can be read or written in bulk.
480 Are endian types PODs?::
481 Yes for {cpp}11. No for {cpp}03, although several
482 <<buffers_compilation,macros>> are available to force PODness in all cases.
484 What are the implications of endian integer types not being PODs with {cpp}03 compilers?::
485 They can't be used in unions. Also, compilers aren't required to align or lay
486 out storage in portable ways, although this potential problem hasn't prevented
487 use of Boost.Endian with real compilers.
489 What good is native endianness?::
490 It provides alignment and size guarantees not available from the built-in
491 types. It eases generic programming.
493 Why bother with the aligned endian types?::
494 Aligned integer operations may be faster (as much as 10 to 20 times faster) if
495 the endianness and alignment of the type matches the endianness and alignment
496 requirements of the machine. The code, however, is likely to be somewhat less
497 portable than with the unaligned types.
499 ## Design considerations for Boost.Endian buffers
501 * Must be suitable for I/O - in other words, must be memcpyable.
502 * Must provide exactly the size and internal byte ordering specified.
503 * Must work correctly when the internal integer representation has more bits
504 that the sum of the bits in the external byte representation. Sign extension
505 must work correctly when the internal integer representation type has more
506 bits than the sum of the bits in the external bytes. For example, using
507 a 64-bit integer internally to represent 40-bit (5 byte) numbers must work for
508 both positive and negative values.
509 * Must work correctly (including using the same defined external
510 representation) regardless of whether a compiler treats char as signed or
512 * Unaligned types must not cause compilers to insert padding bytes.
513 * The implementation should supply optimizations with great care. Experience
514 has shown that optimizations of endian integers often become pessimizations
515 when changing machines or compilers. Pessimizations can also happen when
516 changing compiler switches, compiler versions, or CPU models of the same
521 The availability of the {cpp}11
522 http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2346.htm[Defaulted
523 Functions] feature is detected automatically, and will be used if present to
524 ensure that objects of `class endian_buffer` are trivial, and thus
529 Boost.Endian is implemented entirely within headers, with no need to link to
530 any Boost object libraries.
532 Several macros allow user control over features:
534 * `BOOST_ENDIAN_NO_CTORS` causes `class endian_buffer` to have no
535 constructors. The intended use is for compiling user code that must be
536 portable between compilers regardless of {cpp}11
537 http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2346.htm[Defaulted
538 Functions] support. Use of constructors will always fail,
539 * `BOOST_ENDIAN_FORCE_PODNESS` causes `BOOST_ENDIAN_NO_CTORS` to be defined if
540 the compiler does not support {cpp}11
541 http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2346.htm[Defaulted
542 Functions]. This is ensures that objects of `class endian_buffer` are PODs, and
543 so can be used in {cpp}03 unions. In {cpp}11, `class endian_buffer` objects are
544 PODs, even though they have constructors, so can always be used in unions.