![]() |
![]() ![]() ![]() ![]() ![]() |
![]() |
Endian Buffer TypesBoost , ,
|
Endian Home Функции преобразования Арифметические типы Буферные типы Выбор подхода |
Contents |
Introduction Example Limitations Feature set Enums and typedefs Class template endian_buffer Synopsis Members Non-Members FAQ Design C++11 Compilation |
Внутренний байтовый порядок арифметических типов традиционно называетсяэндианностью. См.Википедиядля полного изученияэндианности, включая определениябольшого эндианаималенького эндиана.
Заголовок<boost/endian/buffers.hpp
>обеспечивает<endian_buffer
>, портативный эндиан-целое двоичный шаблон класса буфера с контролем порядка байта, типа значения, размера и выравнивания, независимо от нативной эндианности платформы & # 39. Typedefs предоставляют простые в использовании имена для общих конфигураций.
Случаи использования в основном связаны с переносимостью данных, либо через файлы, либо через сетевые соединения, но эти держатели байтов также могут использоваться для уменьшения использования памяти, размера файла или сетевой активности, поскольку они обеспечивают двоичные числовые размеры, недоступные в противном случае.
Class endian_buffer
is aimed at users who wish
explicit control over when endianness conversions occur. It also serves as the
base class for the endian_arithmetic
class template, which is aimed at users who wish fully automatic endianness
conversion and direct support for all normal arithmetic operations.
Программа<example/endian_example.cpp
>пишет двоичный файл, содержащий четырехбайтовые, большие и малые эндиановые целые числа:
#include <iostream> #include <cstdio> #include <boost/endian/buffers.hpp> // see Synopsis below #include <boost/static_assert.hpp> using namespace boost::endian; namespace { // This is an extract from a very widely used GIS file format. // Why the designer decided to mix big and little endians in // the same file is not known. 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 { big_int32_buf_
t file_code; big_int32_buf_
t file_length; little_int32_buf_
t version; little_int32_buf_
t shape_type; }; const char* filename = "test.dat"; } int main(int, char* []) { header h; BOOST_STATIC_ASSERT(sizeof(h) == 16U); // reality check h.file_code = 0x01020304; h.file_length = sizeof(header); h.version = 1; h.shape_type = 0x01020304; // 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 = std::fopen(filename, "wb"); // MUST BE BINARY if (!fi) { std::cout << "could not open " << filename << '\n'; return 1; } if (std::fwrite(&h, sizeof(header), 1, fi)!= 1) { std::cout << "write failure for " << filename << '\n'; return 1; } std::fclose(fi); std::cout << "created file " << filename << '\n'; return 0; }
После составления и исполнения<example/endian_example.cpp
>, шестнадцатеричный слив<test.dat
>показывает:
01020304 00000010 01000000 04030201
Обратите внимание, что первые два 32-разрядных целых числа являются большими эндианами, а вторые два — маленькими эндианами, хотя машина, на которой это было составлено и запущено, была малоэндианной.
Для этого требуется<<climits>
><CHAR_BIT == 8
>. Если<CHAR_BIT
>является неким другим значением, то компиляция приведет к<#error
>. Это ограничение существует, потому что при проектировании, внедрении, тестировании и документации учитывались только проблемы, связанные с 8-битными байтами, и не было представлено реальных вариантов использования для других размеров.
В C++03<endian_buffer
>не соответствует требованиям для типов POD, поскольку имеет конструкторы, частные члены данных и базовый класс. Это означает, что общие случаи использования основаны на неопределенном поведении в том, что C++ Стандарт не гарантирует макет памяти для не-POD типов. Это не было проблемой на практике, так как все известные компиляторы C++ выкладывают память, как если бы<
endian
>были POD-типом. В C++11 можно указать конструктор по умолчанию как тривиальный, а частные члены данных и базовые классы больше не дисквалифицируют тип от типа POD. Таким образом, в C++11<endian_buffer
>больше не будет полагаться на неопределенное поведение.
Предусмотрены два тематических перечня:
enum class order {big, little, native}; enum class align {no, yes};
Предоставляется один шаблон класса:
template <order Order, typename T, std::size_t Nbits, align Align = align::no> class endian_buffer;
Типдефы, такие как<big_int32_buf_t
>, обеспечивают удобные соглашения об именах для общих случаев использования:
Name Alignment Endianness Sign Sizes in bits (n) big_int
n_buf_t
no
big
signed 8,16,24,32,40,48,56,64 big_uint
n_buf_t
no
big
unsigned 8,16,24,32,40,48,56,64 little_int
n_buf_t
no
little
signed 8,16,24,32,40,48,56,64 little_uint
n_buf_t
no
little
unsigned 8,16,24,32,40,48,56,64 native_int
n_buf_t
no
native
signed 8,16,24,32,40,48,56,64 native_uint
n_buf_t
no
native
unsigned 8,16,24,32,40,48,56,64 big_int
n_buf_at
yes
big
signed 8,16,32,64 big_uint
n_
buf_at
yes
big
unsigned 8,16,32,64 little_int
n_
buf_at
yes
little
signed 8,16,32,64 little_uint
n_
buf_at
yes
little
unsigned 8,16,32,64
Невыровненные типы не заставляют компиляторы вставлять байты прокладки в классы и структуры. Это важная характеристика, которую можно использовать для минимизации потерянного пространства в памяти, файлах и сетевых передачах.
Предупреждение:Код, который используетзажигаемые типы, возможно, непортативный, потому что требования выравнивания различаются между аппаратными архитектурами и потому, что выравнивание может быть затронуто коммутаторами компилятора или прагмами. Например, выравнивание 64-битного целого числа может быть на 32-битной границе на 32-битной машине и на 64-битной границе на 64-битной машине. Кроме того, выровненные типы доступны только в архитектурах с 8, 16, 32 и 64-разрядными целыми типами.
Рекомендация:Предпочитают неприсоединившиеся типы буферов.
Рекомендация:Защитите себя от болезней выравнивания. Например:
static_assert(sizeof(containing_struct) == 12, "sizeof(containing_struct) is wrong");
Примечание:Однобайтовые большие и маленькие буферные типы имеют одинаковую компоновку на всех платформах, поэтому они никогда не обращают вспять эндианность. Они предоставляются для обеспечения универсального кода, а также для улучшения читаемости и поиска кода.
endian
_buffer
<endian_buffer
>является держателем байта для арифметических типов с эндианностьюпользователя, типом значения, размером ивыравниванием.
#include <boost/endian/conversion.hpp namespace boost { namespace endian { // C++11 features emulated if not available enum class align {no, yes}; template <order Order, class T, std::size_t Nbits, align Align = align::no> class endian_buffer { public: typedef T value_type; endian_buffer() noexcept = default; explicit endian_buffer(T v) noexcept; endian_buffer& operator=(T v) noexcept; value_type value() const noexcept; const char* data() const noexcept; protected: implementaton-defined endian_value; // for exposition only }; // stream inserter template <class charT, class traits, order Order, class T, std::size_t n_bits, align Align> std::basic_ostream<charT, traits>& operator<<(std::basic_ostream<charT, traits>& os, const endian_buffer<Order, T, n_bits, Align>& x); // stream extractor template <class charT, class traits, order Order, class T, std::size_t n_bits, align A> std::basic_istream<charT, traits>& operator>>(std::basic_istream<charT, traits>& is, endian_buffer<Order, T, n_bits, Align>& x); // typedefs // unaligned big endian signed integer buffers typedef endian_buffer<order::big, int_least8_t, 8> big_int8_buf_t; typedef endian_buffer<order::big, int_least16_t, 16> big_int16_buf_t; typedef endian_buffer<order::big, int_least32_t, 24> big_int24_buf_t; typedef endian_buffer<order::big, int_least32_t, 32> big_int32_buf_t; typedef endian_buffer<order::big, int_least64_t, 40> big_int40_buf_t; typedef endian_buffer<order::big, int_least64_t, 48> big_int48_buf_t; typedef endian_buffer<order::big, int_least64_t, 56> big_int56_buf_t; typedef endian_buffer<order::big, int_least64_t, 64> big_int64_buf_t; // unaligned big endian unsigned integer buffers typedef endian_buffer<order::big, uint_least8_t, 8> big_uint8_buf_t; typedef endian_buffer<order::big, uint_least16_t, 16> big_uint16_buf_t; typedef endian_buffer<order::big, uint_least32_t, 24> big_uint24_buf_t; typedef endian_buffer<order::big, uint_least32_t, 32> big_uint32_buf_t; typedef endian_buffer<order::big, uint_least64_t, 40> big_uint40_buf_t; typedef endian_buffer<order::big, uint_least64_t, 48> big_uint48_buf_t; typedef endian_buffer<order::big, uint_least64_t, 56> big_uint56_buf_t; typedef endian_buffer<order::big, uint_least64_t, 64> big_uint64_buf_t; // unaligned little endian signed integer buffers typedef endian_buffer<order::little, int_least8_t, 8> little_int8_buf_t; typedef endian_buffer<order::little, int_least16_t, 16> little_int16_buf_t; typedef endian_buffer<order::little, int_least32_t, 24> little_int24_buf_t; typedef endian_buffer<order::little, int_least32_t, 32> little_int32_buf_t; typedef endian_buffer<order::little, int_least64_t, 40> little_int40_buf_t; typedef endian_buffer<order::little, int_least64_t, 48> little_int48_buf_t; typedef endian_buffer<order::little, int_least64_t, 56> little_int56_buf_t; typedef endian_buffer<order::little, int_least64_t, 64> little_int64_buf_t; // unaligned little endian unsigned integer buffers typedef endian_buffer<order::little, uint_least8_t, 8> little_uint8_buf_t; typedef endian_buffer<order::little, uint_least16_t, 16> little_uint16_buf_t; typedef endian_buffer<order::little, uint_least32_t, 24> little_uint24_buf_t; typedef endian_buffer<order::little, uint_least32_t, 32> little_uint32_buf_t; typedef endian_buffer<order::little, uint_least64_t, 40> little_uint40_buf_t; typedef endian_buffer<order::little, uint_least64_t, 48> little_uint48_buf_t; typedef endian_buffer<order::little, uint_least64_t, 56> little_uint56_buf_t; typedef endian_buffer<order::little, uint_least64_t, 64> little_uint64_buf_t; // unaligned native endian signed integer types typedef implementation-defined_int8_buf_t native_int8_buf_t; typedef implementation-defined_int16_buf_t native_int16_buf_t; typedef implementation-defined_int24_buf_t native_int24_buf_t; typedef implementation-defined_int32_buf_t native_int32_buf_t; typedef implementation-defined_int40_buf_t native_int40_buf_t; typedef implementation-defined_int48_buf_t native_int48_buf_t; typedef implementation-defined_int56_buf_t native_int56_buf_t; typedef implementation-defined_int64_buf_t native_int64_buf_t; // unaligned native endian unsigned integer types typedef implementation-defined_uint8_buf_t native_uint8_buf_t; typedef implementation-defined_uint16_buf_t native_uint16_buf_t; typedef implementation-defined_uint24_buf_t native_uint24_buf_t; typedef implementation-defined_uint32_buf_t native_uint32_buf_t; typedef implementation-defined_uint40_buf_t native_uint40_buf_t; typedef implementation-defined_uint48_buf_t native_uint48_buf_t; typedef implementation-defined_uint56_buf_t native_uint56_buf_t; typedef implementation-defined_uint64_buf_t native_uint64_buf_t; // aligned big endian signed integer buffers typedef endian_buffer<order::big, int8_t, 8, align::yes> big_int8_buf_at; typedef endian_buffer<order::big, int16_t, 16, align::yes> big_int16_buf_at; typedef endian_buffer<order::big, int32_t, 32, align::yes> big_int32_buf_at; typedef endian_buffer<order::big, int64_t, 64, align::yes> big_int64_buf_at; // aligned big endian unsigned integer buffers typedef endian_buffer<order::big, uint8_t, 8, align::yes> big_uint8_buf_at; typedef endian_buffer<order::big, uint16_t, 16, align::yes> big_uint16_buf_at; typedef endian_buffer<order::big, uint32_t, 32, align::yes> big_uint32_buf_at; typedef endian_buffer<order::big, uint64_t, 64, align::yes> big_uint64_buf_at; // aligned little endian signed integer buffers typedef endian_buffer<order::little, int8_t, 8, align::yes> little_int8_buf_at; typedef endian_buffer<order::little, int16_t, 16, align::yes> little_int16_buf_at; typedef endian_buffer<order::little, int32_t, 32, align::yes> little_int32_buf_at; typedef endian_buffer<order::little, int64_t, 64, align::yes> little_int64_buf_at; // aligned little endian unsigned integer buffers typedef endian_buffer<order::little, uint8_t, 8, align::yes> little_uint8_buf_at; typedef endian_buffer<order::little, uint16_t, 16, align::yes> little_uint16_buf_at; typedef endian_buffer<order::little, uint32_t, 32, align::yes> little_uint32_buf_at; typedef endian_buffer<order::little, uint64_t, 64, align::yes> little_uint64_buf_at; // aligned native endian typedefs are not provided because // <cstdint> types are superior for this use case } // namespace endian } // namespace boost
Текст<implementation-defined
>в типоразмерах выше либо<big
>, либо<little
>в соответствии с родной эндианностью платформы.
Экспозиторный элемент данных<endian_value
>сохраняет текущее значение объекта<endian_value
>в виде последовательности байтов, упорядоченных в соответствии с параметром шаблона<Order
>. Тип<
implementation-defined
><endian_value
>- это тип<char[Nbits/CHAR_BIT]
>или<T
>, который соответствует требованиям, предъявляемым параметрами шаблона<Nbits
>и<Align
>. Макро<CHAR_BIT
>определено в<<climits>
>. Единственное значение<CHAR_BIT
>, которое необходимо поддерживать, составляет 8.
Параметр шаблона<T
>должен быть стандартным целым типом (C++std, 3.9.1) и<
sizeof(T)*CHAR_BIT
>должен быть больше или равен<Nbits
>.
endian_buffer() noexcept = default;
Эффекты:Построение неинициализированного объекта типа<
endian_buffer<Order, T, Nbits, Align>
>.
explicit endian_buffer(T v) noexcept;
Эффекты:Конструирует объект типа<
endian_buffer<Order, T, Nbits, Align>
>.Постусловие:<
value() == v & mask
>, где<mask
>является константой типа<value_type
>с<Nbits
>битами низкого порядка, установленными на один.Замечания:Если<
Align
>является<align::yes
>, то преобразование эндианности, если требуется, выполняется<boost::endian::endian_reverse
>.
endian_buffer& operator=(T v) noexcept;
Постусловие:<
value() == v & mask
>, где<mask
>является константой типа<value_type
>с<Nbits
>битами низкого порядка, установленными на один.Возвращение:<
*this
>.Замечания:Если<
Align
>является<align::yes
>, то преобразование эндианности, если требуется, выполняется<boost::endian::endian_reverse
>.
value_type value() const noexcept;
Возвращается:<
endian_value
>, преобразуется в<value_type
>, если требуется, и имеет эндианность родной платформы.Замечания:Если<
Align
>является<align::yes
>, то преобразование эндианности, если требуется, выполняется<boost::endian::endian_reverse
>.
const char* data() const noexcept;
Возврат:Указатель на первый байт<
endian_value
>.
template <class charT, class traits, order Order, class T, std::size_t n_bits, align Align> std::basic_ostream<charT, traits>& operator<<(std::basic_ostream<charT, traits>& os, const endian_buffer<Order, T, n_bits, Align>& x);
Возвращение:<
os << x.value()
>.
template <class charT, class traits, order Order, class T, std::size_t n_bits, align A> std::basic_istream<charT, traits>& operator>>(std::basic_istream<charT, traits>& is, endian_buffer<Order, T, n_bits, Align>& x);
Эффекты:Как будто:
T i; if (is >> i) x = i;Возвращение:<
is
>.
См. домашнюю страницуEndianFAQ для FAQ в библиотеке.
Почему бы просто не использовать Boost.Serialization?Сериализация включает в себя преобразование для каждого объекта, участвующего в I/O. Эндиевые целые числа не требуют преобразования или копирования. Они уже в нужном формате для двоичного ввода/вывода. Таким образом, их можно читать или писать навалом.
Являются ли эндианские типы POD?Да, для C++11. Нет для C++03, хотя несколькомакросовдоступны для форсирования PODness во всех случаях.
Каковы последствия того, что целые типы эндиев не являются POD с компиляторами C++03?Они не могут использоваться в профсоюзах. Кроме того, компиляторы не обязаны выравнивать или размещать хранилище портативными способами, хотя эта потенциальная проблема не помешала использованию Boost. Эндиан с реальными компиляторами.
Что хорошего вродномэндианстве?Он обеспечивает выравнивание и гарантии размера, недоступные для встроенных типов. Упрощает общее программирование.
Зачем беспокоиться о выровненных типах эндиев?Выровненные целые операции могут быть быстрее (в 10-20 раз быстрее), если эндианность и выравнивание типа соответствуют требованиям эндианности и выравнивания машины. Код, однако, вероятно, будет несколько менее портативным, чем с неприсоединившимися типами.
Доступность функции C++11Defaulted Functionsобнаруживается автоматически и будет использоваться, если она присутствует, для обеспечения того, чтобы объекты<class endian_buffer
>были тривиальными и, следовательно, POD.
Повышаю. Endian полностью реализован в заголовках, без необходимости ссылаться на какие-либо библиотеки объектов Boost.
Несколько макросов позволяют пользователю контролировать функции:
class endian_buffer
являются POD, и поэтому могут использоваться в союзах C++03. В C++11class endian_buffer
объекты являются POD, хотя у них есть конструкторы, поэтому их всегда можно использовать в союзах.Последнее изменение:14 октября 201514 October, 2015[ORIG_END] -->
© Copyright Beman Dawes, 2006-2009, 2013
Распространяется в соответствии с Лицензией на программное обеспечение Boost, версия 1.0. См.www.boost.org/ LICENSE_1_0.txt
Статья Endian Buffer Types раздела может быть полезна для разработчиков на c++ и boost.
Материалы статей собраны из открытых источников, владелец сайта не претендует на авторство. Там где авторство установить не удалось, материал подаётся без имени автора. В случае если Вы считаете, что Ваши права нарушены, пожалуйста, свяжитесь с владельцем сайта.
:: Главная :: ::
реклама |