From 0f36e2670d05f139e4161fc9b5797c83657cd025 Mon Sep 17 00:00:00 2001 From: bemandawes Date: Thu, 19 Mar 2009 14:33:59 +0000 Subject: [PATCH] Endian: docs and examples improvements git-svn-id: http://svn.boost.org/svn/boost/sandbox/endian@51855 b8fc166d-592f-0410-95f2-cb63ce0dd405 --- boost/integer/endian.hpp | 8 +- boost/integer/endian_binary_stream.hpp | 5 +- libs/integer/doc/endian.html | 132 ++++++++++++++++---- libs/integer/example/endian_example.cpp | 23 ++-- libs/integer/example/endian_hello_world.cpp | 10 +- libs/integer/test/endian_in_union_test.cpp | 2 +- 6 files changed, 133 insertions(+), 47 deletions(-) diff --git a/boost/integer/endian.hpp b/boost/integer/endian.hpp index fb2584d..047b217 100644 --- a/boost/integer/endian.hpp +++ b/boost/integer/endian.hpp @@ -39,13 +39,13 @@ # error Platforms with CHAR_BIT != 8 are not supported # endif -# ifndef BOOST_NO_DEFAULTED_FUNCTIONS -# define BOOST_ENDIAN_DEFAULT_CONSTRUCT = default; // C++0x -# else +# ifdef BOOST_NO_DEFAULTED_FUNCTIONS # define BOOST_ENDIAN_DEFAULT_CONSTRUCT {} // C++03 +# else +# define BOOST_ENDIAN_DEFAULT_CONSTRUCT = default; // C++0x # endif -# if defined(BOOST_NO_DEFAULTED_FUNCTIONS) && defined(BOOST_ENDIANS_IN_UNIONS) +# if defined(BOOST_NO_DEFAULTED_FUNCTIONS) && defined(BOOST_ENDIAN_FORCE_PODNESS) # define BOOST_ENDIAN_NO_CTORS # endif diff --git a/boost/integer/endian_binary_stream.hpp b/boost/integer/endian_binary_stream.hpp index 94c062b..9e016aa 100644 --- a/boost/integer/endian_binary_stream.hpp +++ b/boost/integer/endian_binary_stream.hpp @@ -15,9 +15,10 @@ #include #include -// unformatted binary (as opposed to formatted character-set) input and output +// unformatted binary (as opposed to formatted character) stream insertion +// and extraction. -// Caution: Use only on streams opened with filemode std::ios_base::binary. Thus +// Warning: Use only on streams opened with filemode std::ios_base::binary. 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. diff --git a/libs/integer/doc/endian.html b/libs/integer/doc/endian.html index ce4ac14..9dd8f71 100644 --- a/libs/integer/doc/endian.html +++ b/libs/integer/doc/endian.html @@ -37,6 +37,7 @@ Introduction
+ Hello endian world
Limitations
Feature set
Typedefs
@@ -46,9 +47,12 @@ Synopsis
    Members
FAQ
+ Binary I/O warnings and cautions
Example
Design
Experience
+ C++0x
+ Compilation
Acknowledgements @@ -59,7 +63,8 @@ <boost/integer/endian.hpp>
- <boost/integer/endian_io.hpp> + <boost/integer/endian_binary_stream.hpp>
+ <boost/binary_stream.hpp>

Introduction

@@ -70,7 +75,7 @@ byte order, value type, size, and alignment. Typedefs provide easy-to-use names for common configurations.

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 portability is the primary motivation, these +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.

@@ -91,9 +96,43 @@ arithmetic operators are +, +=, -, >>=. Binary relational operators are ==, !=, <, <=, >, >=.

Automatic conversion is provided to the underlying integer value type.

-

Header <boost/integer/endian_io.hpp> -provides operators << and >> for -stream insertion and extraction.

+

Header <boost/integer/endian_binary_stream.hpp> +provides operators <= and => for unformatted binary (as opposed to +formatted character) stream insertion and extraction of endian types.

+

Header <boost/binary_stream.hpp> +provides operators <= and => for unformatted binary (as opposed to +formatted character) stream insertion and extraction of built-in and std::string +types.

+

Hello endian world

+
+
#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';
+}
+
+

On a little-endian CPU, this program outputs:

+
+
Hello, endian world!
+
+825373492 825373492 825373492
+4321 1234 4321
+

Limitations

Requires <climits> CHAR_BIT == 8. If CHAR_BIT is some other value, compilation will result in an #error. This @@ -395,11 +434,9 @@ alignment.

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.

-

Are endian types POD's? In C++03, no. For C++0x, yes, after applying - -= -default to the default constructor.

-

What are the implications of C++03 endian types not being POD's? They +

Are endian types POD's? Yes for C++0x. No for C++03, although several +macros are available to force PODness in all cases.

+

What are the implications endian types not being POD's of C++03? They can't be used in unions. In theory, compilers aren't required to align or lay out storage in portable ways, although this problem has never been observed in a real compiler.

@@ -428,6 +465,27 @@ incrementing a variable in a record. It is very convenient to write:

    int temp( record.foo);
     ++temp;
     record.foo = temp;
+

Why do binary stream insertion and extraction use operators <= and >= +rather than <<= and >>=? <<= and >>= associate right-to-left, which is the +opposite of << and >>, so would be very confusing and error prone. <= and >= +associate left-to-right.

+

Binary I/O warnings and cautions

+

Warning:  Use +only on streams opened with filemode std::ios_base::binary. 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.

+

Caution: +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:

+
+
my_stream << foo <= bar;    // no parentheses needed
+(my_stream <= foo) << bar;  // parentheses required 
+
+

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.

Example

The endian_example.cpp program writes a binary file containing four byte big-endian and little-endian integers:

@@ -437,15 +495,14 @@ binary file containing four byte big-endian and little-endian integers:

#include <cstdio> #include <boost/integer/endian.hpp> -using boost::integer::big32_t; -using boost::integer::little32_t; +using namespace boost::integer; namespace { - // This is a portion of a widely used GIS file format. I have no idea why - // anyone would mix big and little endians in the same format - but it is - // a real format and users wishing to write code manipulating files in that - // format have to deal with it. + // 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 { @@ -460,7 +517,7 @@ namespace int main() { - assert( sizeof( header ) == 16 ); + assert( sizeof( header ) == 16 ); // requirement for interoperability header h; @@ -469,15 +526,15 @@ int main() h.version = -1; h.shape_type = 0x04030201; - // Low-level I/O such as POSIX read/write or <cstdio> fread/fwrite is - // typically used for binary file operations. Such I/O is often performed in - // some C++ wrapper class, but to drive home the point that endian integers - // are usually used in fairly low-level code, <cstdio> fopen/fwrite is used - // for I/O in this example. + // 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" )) ) + if ( !(fi = std::fopen( filename, "wb" )) ) // MUST BE BINARY { std::cout << "could not open " << filename << '\n'; return 1; @@ -490,6 +547,7 @@ int main() } std::fclose( fi ); + std::cout << "created file " << filename << '\n'; return 0; } @@ -527,6 +585,30 @@ 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.

+

C++0x

+

The availability of the C++0x + +Defaulted Functions feature is detected automatically, and will be used if +present to ensure that objects of class endian are trivial, and +thus POD's.

+

Compilation

+

Boost.Endian is implemented entirely within headers, with no need to link to +any Boost object libraries.

+

Several macros allow user control over features:

+
    +
  • BOOST_ENDIAN_NO_CTORS causes class endian to have no + constructors. The intended use is for compiling user code that must be + portable between compilers regardless of C++0x + + Defaulted Functions support. Use of constructors will always fail,
  • +
  • BOOST_ENDIAN_FORCE_PODNESS causes BOOST_ENDIAN_NO_CTORS to be defined if + the compiler does not support C++0x + + Defaulted Functions. This is ensures that , and so can be used in unions. + In C++0x, class endian objects are POD's even though they have + constructors.
  • +

Acknowledgements

Original design developed by Darin Adler based on classes developed by Mark Borgerding. Four original class templates combined into a single endian @@ -553,8 +635,8 @@ Tomas Puverle, and Yuval Ronen.


Last revised: -12 March, 2009

-

© Copyright Beman Dawes, 2006

+19 March, 2009

+

© Copyright Beman Dawes, 2006-2009

Distributed under the Boost Software License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at www.boost.org/ LICENSE_1_0.txt)

diff --git a/libs/integer/example/endian_example.cpp b/libs/integer/example/endian_example.cpp index 05a994f..fb53c71 100644 --- a/libs/integer/example/endian_example.cpp +++ b/libs/integer/example/endian_example.cpp @@ -2,8 +2,8 @@ // Copyright Beman Dawes, 2006 -// Distributed under the Boost Software License, Version 1.0. (See accompanying -// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// Distributed under the Boost Software License, Version 1.0. +// See http://www.boost.org/LICENSE_1_0.txt // See library home page at http://www.boost.org/libs/endian @@ -16,14 +16,13 @@ #include #include -using boost::integer::big32_t; -using boost::integer::little32_t; +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 format and users wishing to write low level code + // 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 @@ -39,7 +38,7 @@ namespace int main() { - assert( sizeof( header ) == 16 ); + assert( sizeof( header ) == 16 ); // requirement for interoperability header h; @@ -48,15 +47,15 @@ int main() h.version = -1; h.shape_type = 0x04030201; - // Low-level I/O such as POSIX read/write or fread/fwrite is - // typically used for binary file operations. Such I/O is often performed in - // some C++ wrapper class, but to drive home the point that endian integers - // are usually used in fairly low-level code, fopen/fwrite is used - // for I/O in this example. + // Low-level I/O such as POSIX read/write or 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, fopen/fwrite is used for I/O in this example. std::FILE * fi; - if ( !(fi = std::fopen( filename, "wb" )) ) + if ( !(fi = std::fopen( filename, "wb" )) ) // MUST BE BINARY { std::cout << "could not open " << filename << '\n'; return 1; diff --git a/libs/integer/example/endian_hello_world.cpp b/libs/integer/example/endian_hello_world.cpp index a8a1a8d..fc600a8 100644 --- a/libs/integer/example/endian_hello_world.cpp +++ b/libs/integer/example/endian_hello_world.cpp @@ -19,8 +19,12 @@ int main() { int_least32_t v = 0x31323334L; // = ASCII { '1', '2', '3', '4' } // value chosen to work on text stream - std::cout << "Hello, endian world!\n"; - std::cout << v << " " << big32_t(v) << " " << little32_t(v) << '\n'; - std::cout <= v <= ' ' <= big32_t(v) <= ' ' <= little32_t(v) <= '\n'; + 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'; } diff --git a/libs/integer/test/endian_in_union_test.cpp b/libs/integer/test/endian_in_union_test.cpp index 6755f5e..37b246d 100644 --- a/libs/integer/test/endian_in_union_test.cpp +++ b/libs/integer/test/endian_in_union_test.cpp @@ -9,7 +9,7 @@ //----------------------------------------------------------------------------// -#define BOOST_ENDIANS_IN_UNIONS +#define BOOST_ENDIAN_FORCE_PODNESS #include #include