![]() |
![]() ![]() ![]() ![]() ![]() |
![]() |
Endian Arithmetic TypesBoost , ,
|
Endian Home Функции преобразования Арифметические типы Буферные типы Выбор подхода |
Headerboost/endian/arithmetic.hppобеспечивает целые двоичные типы с контролем порядка байтов, типа значений, размера и выравнивания. Typedefs предоставляют простые в использовании имена для общих конфигураций.
Эти типы предоставляют портативные держатели байтов для целочисленных данных, независимо от конкретных компьютерных архитектур. Случаи использования почти всегда включают в себя ввод/вывод либо через файлы, либо через сетевые соединения. Хотя переносимость данных является основной мотивацией, эти целочисленные держатели байтов могут также использоваться для уменьшения использования памяти, размера файла или сетевой активности, поскольку они обеспечивают двоичные целочисленные размеры, недоступные в противном случае.
Такие целочисленные байтодержатели традиционно называютэндианамитипами. См.Википедиядля полного изученияэндианности, включая определениябольшого эндианаималенького эндиана.
Эндиевые целые числа Boost обеспечивают тот же полный набор назначений C++, арифметических и реляционных операторов как стандартные интегральные типы C++ со стандартной семантикой.
Унарными арифметическими операторами являются<+
>,<-
>,<~
>,<!
>, плюс префикс и постфикс<--
>и<++
>. Бинарные арифметические операторы:<+
>,<+=
>,<-
>,<
-=
>,<*
>,<*=
>,</
>,</=
>,<&
>,<&=
>,<|
>,<|=
>,<^
>,<^=
>,<<<
>,<<<=
>,<
>>
>и<>>=
>. Бинарные реляционные операторы:<==
>,<!=
>,<<
>,<<=
>,<>
>и<>=
>.
Предусмотрена неявная конверсия в базовый тип стоимости. Предоставляется неявный конструктор, конвертирующий из базового типа значения.
Программаendian_example.cppпишет двоичный файл, содержащий четырехбайтовые, большие и малые целые числа:
#include <iostream> #include <cstdio> #include <boost/endian/arithmetic.hpp> #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_t file_code; big_int32_t file_length; little_int32_t version; little_int32_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; }
После компиляции и выполненияendian_example.cpp, шестнадцатеричный слив<test.dat
>показывает:
01020304 00000010 01000000 04030201
Обратите внимание, что первые два 32-разрядных целых числа являются большими эндианами, а вторые два — маленькими эндианами, хотя машина, на которой это было составлено и запущено, была малоэндианной.
Для этого необходимо<<climits>
><CHAR_BIT == 8
>. Если<CHAR_BIT
>является неким другим значением, то компиляция приведет к<#error
>. Это ограничение существует, потому что при проектировании, внедрении, тестировании и документации учитывались только проблемы, связанные с 8-битными байтами, и не было представлено реальных вариантов использования для других размеров.
В C++03<endian_arithmetic
>не соответствует требованиям для типов POD, поскольку имеет конструкторы, частные члены данных и базовый класс. Это означает, что общие случаи использования основаны на неопределенном поведении в том, что C++ Стандарт не гарантирует макет памяти для не-POD типов. Это не было проблемой на практике, так как все известные компиляторы C++ выкладывают память, как если бы<
endian
>были POD-типом. В C++11 можно указать конструктор по умолчанию как тривиальный, а частные члены данных и базовые классы больше не дисквалифицируют тип от типа POD. Таким образом, в C++11<endian_arithmetic
>больше не будет полагаться на неопределенное поведение.
Предусмотрены два тематических перечня:
enum class order {big, little, native}; enum class align {no, yes};
Предоставляется один шаблон класса:
template <order Order, typename T, std::size_t n_bits, align Align = align::no> class endian_arithmetic;
Типдефы, такие как<big_int32_t
>, обеспечивают удобные соглашения об именах для общих случаев использования:
Name Alignment Endianness Sign Sizes in bits (n) big_int
n_t
no
big
signed 8,16,24,32,40,48,56,64 big_uint
n_t
no
big
unsigned 8,16,24,32,40,48,56,64 little_int
n_t
no
little
signed 8,16,24,32,40,48,56,64 little_uint
n_t
no
little
unsigned 8,16,24,32,40,48,56,64 native_int
n_t
no
native
signed 8,16,24,32,40,48,56,64 native_uint
n_t
no
native
unsigned 8,16,24,32,40,48,56,64 big_int
n_at
yes
big
signed 8,16,32,64 big_uint
n_at
yes
big
unsigned 8,16,32,64 little_int
n_at
yes
little
signed 8,16,32,64 little_uint
n_at
yes
little
unsigned 8,16,32,64
Невыровненные типы не заставляют компиляторы вставлять байты прокладки в классы и структуры. Это важная характеристика, которую можно использовать для минимизации потерянного пространства в памяти, файлах и сетевых передачах.
Предупреждение:Код, который используетзажигаемые типы, возможно, непортативный, потому что требования выравнивания различаются между аппаратными архитектурами и потому, что выравнивание может быть затронуто коммутаторами компилятора или прагмами. Например, выравнивание 64-битного целого числа может быть на 32-битной границе на 32-битной машине. Кроме того, выровненные типы доступны только в архитектурах с 8, 16, 32 и 64-разрядными целыми типами.
Рекомендация:Предпочитают невыровненные арифметические типы.
Рекомендация:Защитите себя от болезней выравнивания. Например:
static_assert(sizeof(containing_struct) == 12, "sizeof(containing_struct) is wrong");
Примечание:Примечание:Однобайтовые арифметические типы имеют одинаковую компоновку на всех платформах, поэтому они никогда не обращают вспять эндианность. Они предоставляются для обеспечения универсального кода, а также для улучшения читаемости и поиска кода.
endian
_arithmetic
<endian_integer
>представляет собой целочисленный байтодержатель с эндианностьюпользователя, типом значения, размером ивыравниванием. Поставляются обычные операции по арифметическим типам.
#include <boost/endian/conversion.hpp> #include <boost/endian/buffers.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 n_bits, align Align = align::no> class endian_arithmetic : public endian_buffer<Order, T, n_bits, Align> { public: typedef T value_type; // if BOOST_ENDIAN_FORCE_PODNESS is defined && C++11 PODs are not // available then these two constructors will not be present endian_arithmetic() noexcept = default; endian_arithmetic(T v) noexcept; endian_arithmetic& operator=(T v) noexcept; operator value_type() const noexcept; value_type value() const noexcept; // for exposition; see endian_buffer const char* data() const noexcept; // for exposition; see endian_buffer // arithmetic operations // note that additional operations are provided by the value_type value_type operator+(const endian& x) noexcept; endian& operator+=(endian& x, value_type y) noexcept; endian& operator-=(endian& x, value_type y) noexcept; endian& operator*=(endian& x, value_type y) noexcept; endian& operator/=(endian& x, value_type y) noexcept; endian& operator%=(endian& x, value_type y) noexcept; endian& operator&=(endian& x, value_type y) noexcept; endian& operator|=(endian& x, value_type y) noexcept; endian& operator^=(endian& x, value_type y) noexcept; endian& operator<<=(endian& x, value_type y) noexcept; endian& operator>>=(endian& x, value_type y noexcept; value_type operator<<(const endian& x, value_type y) noexcept; value_type operator>>(const endian& x, value_type y) noexcept; endian& operator++(endian& x) noexcept; endian& operator--(endian& x) noexcept; endian operator++(endian& x, int) noexcept; endian operator--(endian& x, int) noexcept; // Stream inserter template <class charT, class traits> friend std::basic_ostream<charT, traits>& operator<<(std::basic_ostream<charT, traits>& os, const T& x); // Stream extractor template <class charT, class traits> friend std::basic_istream<charT, traits>& operator>>(std::basic_istream<charT, traits>& is, T& x); }; // typedefs // unaligned big endian signed integer types typedef endian<order::big, int_least8_t, 8> big_int8_t; typedef endian<order::big, int_least16_t, 16> big_int16_t; typedef endian<order::big, int_least32_t, 24> big_int24_t; typedef endian<order::big, int_least32_t, 32> big_int32_t; typedef endian<order::big, int_least64_t, 40> big_int40_t; typedef endian<order::big, int_least64_t, 48> big_int48_t; typedef endian<order::big, int_least64_t, 56> big_int56_t; typedef endian<order::big, int_least64_t, 64> big_int64_t; // unaligned big endian unsigned integer types typedef endian<order::big, uint_least8_t, 8> big_uint8_t; typedef endian<order::big, uint_least16_t, 16> big_uint16_t; typedef endian<order::big, uint_least32_t, 24> big_uint24_t; typedef endian<order::big, uint_least32_t, 32> big_uint32_t; typedef endian<order::big, uint_least64_t, 40> big_uint40_t; typedef endian<order::big, uint_least64_t, 48> big_uint48_t; typedef endian<order::big, uint_least64_t, 56> big_uint56_t; typedef endian<order::big, uint_least64_t, 64> big_uint64_t; // unaligned little endian signed integer types typedef endian<order::little, int_least8_t, 8> little_int8_t; typedef endian<order::little, int_least16_t, 16> little_int16_t; typedef endian<order::little, int_least32_t, 24> little_int24_t; typedef endian<order::little, int_least32_t, 32> little_int32_t; typedef endian<order::little, int_least64_t, 40> little_int40_t; typedef endian<order::little, int_least64_t, 48> little_int48_t; typedef endian<order::little, int_least64_t, 56> little_int56_t; typedef endian<order::little, int_least64_t, 64> little_int64_t; // unaligned little endian unsigned integer types typedef endian<order::little, uint_least8_t, 8> little_uint8_t; typedef endian<order::little, uint_least16_t, 16> little_uint16_t; typedef endian<order::little, uint_least32_t, 24> little_uint24_t; typedef endian<order::little, uint_least32_t, 32> little_uint32_t; typedef endian<order::little, uint_least64_t, 40> little_uint40_t; typedef endian<order::little, uint_least64_t, 48> little_uint48_t; typedef endian<order::little, uint_least64_t, 56> little_uint56_t; typedef endian<order::little, uint_least64_t, 64> little_uint64_t; // unaligned native endian signed integer types typedef implementation-defined_int8_t native_int8_t; typedef implementation-defined_int16_t native_int16_t; typedef implementation-defined_int24_t native_int24_t; typedef implementation-defined_int32_t native_int32_t; typedef implementation-defined_int40_t native_int40_t; typedef implementation-defined_int48_t native_int48_t; typedef implementation-defined_int56_t native_int56_t; typedef implementation-defined_int64_t native_int64_t; // unaligned native endian unsigned integer types typedef implementation-defined_uint8_t native_uint8_t; typedef implementation-defined_uint16_t native_uint16_t; typedef implementation-defined_uint24_t native_uint24_t; typedef implementation-defined_uint32_t native_uint32_t; typedef implementation-defined_uint40_t native_uint40_t; typedef implementation-defined_uint48_t native_uint48_t; typedef implementation-defined_uint56_t native_uint56_t; typedef implementation-defined_uint64_t native_uint64_t; // aligned big endian signed integer types typedef endian<order::big, int8_t, 8, align::yes> big_int8_at; typedef endian<order::big, int16_t, 16, align::yes> big_int16_at; typedef endian<order::big, int32_t, 32, align::yes> big_int32_at; typedef endian<order::big, int64_t, 64, align::yes> big_int64_at; // aligned big endian unsigned integer types typedef endian<order::big, uint8_t, 8, align::yes> big_uint8_at; typedef endian<order::big, uint16_t, 16, align::yes> big_uint16_at; typedef endian<order::big, uint32_t, 32, align::yes> big_uint32_at; typedef endian<order::big, uint64_t, 64, align::yes> big_uint64_at; // aligned little endian signed integer types typedef endian<order::little, int8_t, 8, align::yes> little_int8_at; typedef endian<order::little, int16_t, 16, align::yes> little_int16_at; typedef endian<order::little, int32_t, 32, align::yes> little_int32_at; typedef endian<order::little, int64_t, 64, align::yes> little_int64_at; // aligned little endian unsigned integer types typedef endian<order::little, uint8_t, 8, align::yes> little_uint8_at; typedef endian<order::little, uint16_t, 16, align::yes> little_uint16_at; typedef endian<order::little, uint32_t, 32, align::yes> little_uint32_at; typedef endian<order::little, uint64_t, 64, align::yes> little_uint64_at; // aligned native endian typedefs are not provided because // <cstdint> types are superior for that use case } // namespace endian } // namespace boost
Текст<implementation-defined
>выше либо<big
>, либо<little
>в соответствии с эндианностью платформы.
endian() = default; // C++03: endian(){}
Эффекты:Конструирует неинициализированный объект типа<
endian_arithmetic<E, T, n_bits, A>
>.
endian(T v);
Эффекты:Конструирует объект типа<
endian_arithmetic<E, T, n_bits, A>
>.Постсостояние:<
x == v,
>, где<x
>является сконструированным объектом.
endian& operator=(T v);
Постсостояние:<
x == v,
>, где<x
>является сконструированным объектом.Возвращение:<
*this
>.
operator T() const;
Возвращение:Текущее значение, сохраненное в<
*this
>, преобразовано в<value_type
>.
const char* data() const;
Возврат:Указатель на первый байт эндианового двоичного значения, хранящегося в<
*this
>.
Другие операторы на эндианных объектах направляются эквивалентному оператору на<value_type
>.
template <class charT, class traits> friend std::basic_ostream<charT, traits>& operator<<(std::basic_ostream<charT, traits>& os, const T& x);
Возвращение:<
os << +x
>.
template <class charT, class traits> friend std::basic_istream<charT, traits>& operator>>(std::basic_istream<charT, traits>& is, T& 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 раз быстрее), если эндианность и выравнивание типа соответствуют требованиям эндианности и выравнивания машины. Код, однако, будет несколько менее портативным, чем с неприсоединившимися типами.
Зачем проводить арифметические операции?Предоставление полного набора операций уменьшает загромождение программ и облегчает запись и чтение кода. Рассмотрите возможность увеличения переменной в записи. Очень удобно писать:
++record.foo;
Rather than:
int temp(record.foo); ++temp; record.foo = temp;
Классы с аналогичной функциональностью были независимо разработаны несколькими программистами Boost и в течение многих лет успешно использовались в высококачественных приложениях. Эти независимо разработанные эндианные библиотеки часто развивались из библиотек C, которые также широко использовались. Типы Endian оказались широко полезными в широком спектре компьютерных архитектур и приложений.
Нил Мэйхью пишет: "Я также могу предоставить значимый вариант использования для этой библиотеки: чтение Правды Введите файлы шрифтов с диска и обработайте содержимое. Формат данных имеет фиксированную эндианность (большую) и имеет несогласованные значения в различных местах. Используя Boost. Эндиан прекрасно упрощает и очищает код. ";
Доступность функции C++11Defaulted Functionsобнаруживается автоматически и будет использоваться, если присутствует, для обеспечения того, чтобы объекты<class endian_arithmetic
>были тривиальными, и, следовательно, POD.
Повышаю. Endian полностью реализован в заголовках, без необходимости ссылаться на какие-либо библиотеки объектов Boost.
Несколько макросов позволяют пользователю контролировать функции:
class endian_arithmetic
являются POD, и поэтому могут использоваться в союзах C++03. В C++11class endian_arithmetic
объекты являются POD, хотя у них есть конструкторы, поэтому их всегда можно использовать в союзах.Оригинальный дизайн разработан Дарином Адлером на основе классов, разработанных Марком Боргердингом. Четыре оригинальных шаблона классов, объединенных в один<endian_arithmetic
>шаблон класса Беманом Доусом, который собрал библиотеку вместе, предоставил документацию, добавил типдефы, а также добавил<unrolled_byte_loops
>знак частичной специализации, чтобы правильно расширить знак, когда размер покрытия целым числом отличается от размера эндианного представления.
Последнее изменение:14 октября 201514 October, 2015[ORIG_END] -->
© Copyright Beman Dawes, 2006-2009, 2013
Распространяется в соответствии с Лицензией на программное обеспечение Boost, версия 1.0. См.www.boost.org/ LICENSE_1_0.txt
Статья Endian Arithmetic Types раздела может быть полезна для разработчиков на c++ и boost.
Материалы статей собраны из открытых источников, владелец сайта не претендует на авторство. Там где авторство установить не удалось, материал подаётся без имени автора. В случае если Вы считаете, что Ваши права нарушены, пожалуйста, свяжитесь с владельцем сайта.
:: Главная :: ::
реклама |