3

Click here to load reader

Урок 19. Паттерн 11. Сериализация и обмен данными

Embed Size (px)

DESCRIPTION

Важным элементом переноса программного решения на новую платформу является преемственность к существующим протоколам обмена данными. Необходимо обеспечить чтение существующих форматов проектов, осуществлять обмен данными между 32-битными и 64-битными процессами и так далее.

Citation preview

Page 1: Урок 19. Паттерн 11. Сериализация и обмен данными

Урок 19. Паттерн 11. Сериализация и

обмен данными

Важным элементом переноса программного решения на новую платформу является

преемственность к существующим протоколам обмена данными. Необходимо обеспечить чтение

существующих форматов проектов, осуществлять обмен данными между 32-битными и 64-

битными процессами и так далее.

В основном, ошибки данного рода заключаются в сериализации memsize-типов и операциях

обмена данными с их использованием:

1) size_t PixelsCount;

fread(&PixelsCount, sizeof(PixelsCount), 1, inFile);

2) __int32 value_1;

SSIZE_T value_2;

inputStream >> value_1 >> value_2;

В приведенных примерах имеются ошибки двух видов: использование типов непостоянной

размерности в бинарных интерфейсах и игнорирование порядка байт.

Использование типов непостоянной размерности

Недопустимо использование типов, которые меняют свой размер в зависимости от среды

разработки, в бинарных интерфейсах обмена данными. В языке Си++ все типы не имеют четкого

размера и, следовательно, их все невозможно использовать для этих целей. Поэтому создатели

средств разработки и сами программисты создают типы данных, имеющие строгий размер, такие

как __int8, __int16, INT32, word64 и так далее.

Использование подобных типов обеспечивает переносимость данных между программами на

различных платформах, хотя и требует дополнительных усилий. Два показанных примера

написаны неаккуратно, что даст о себе знать при смене разрядности некоторых типов данных с 32

бит до 64 бит. Учитывая необходимость поддержки старых форматов данных, исправление может

выглядеть следующим образом:

1) size_t PixelsCount;

__uint32 tmp;

fread(&tmp, sizeof(tmp), 1, inFile);

PixelsCount = static_cast<size_t>(tmp);

2) __int32 value_1;

__int32 value_2;

inputStream >> value_1 >> value_2;

Page 2: Урок 19. Паттерн 11. Сериализация и обмен данными

Но приведенный вариант исправления может являться не лучшим. При переходе на 64-битную

систему программа может обрабатывать большее количество данных, и использование в данных

32-битных типов может стать существенным препятствием. В таком случае, можно оставить

старый код для совместимости со старым форматом данных, исправив некорректные типы. И

реализовать новый бинарный формат данных уже с учетом допущенных ранее ошибок. Еще

одним вариантом может стать отказ от бинарных форматов и переход на текстовый формат или

другие форматы, предоставляемые различными библиотеками.

Игнорирование порядка байт (byte order)

Даже после внесения исправлений, касающихся размеров типа, вы можете столкнуться с

несовместимостью бинарных форматов. Причина кроется в ином представлении данных.

Наиболее часто это связано с другой последовательностью байт.

Порядок байт - метод записи байтов многобайтовых чисел (см. также рисунок 1). Порядок от

младшего к старшему (англ. little-endian) - запись начинается с младшего и заканчивается

старшим. Этот порядок записи принят в памяти персональных компьютеров с x86 и x86-64-

процессорами. Порядок от старшего к младшему (англ. big-endian) - запись начинается со

старшего и заканчивается младшим. Этот порядок является стандартным для протоколов TCP/IP.

Поэтому, порядок байтов от старшего к младшему часто называют сетевым порядком байтов

(англ. network byte order). Этот порядок байт используется процессорами Motorola 68000, SPARC.

Рисунок 1 - Порядок байт в 64-битном типе на little-endian и big-endian системах

Разрабатывая бинарный интерфейс или формат данных, следует помнить о последовательности

байт. А если 64-битная система, на которую Вы переносите 32-битное приложение, имеет иную

последовательность байт, то вы просто будете вынуждены учесть это в своем коде. Для

преобразования между сетевым порядком байт (big-endian) и порядком байт (little-endian), можно

использовать функции htonl(), htons(), bswap_64, и так далее.

Примечание. Во многих системах отсутствуют функции подобные bswap_64. А функция ntohl()

позволяет перевертывать только 32-битные значения. Про вариант этой функции для 64-

битных типов как-то забыли. Если вам нужно поменять порядок байт в 64-битной

Page 3: Урок 19. Паттерн 11. Сериализация и обмен данными

переменной, то на сайте stackoverflow.com имеется обсуждение темы "64 bit ntohl() in C++ ?"

где приведено сразу несколько примеров реализации такой функции.

Диагностика

К сожалению PVS-Studio не реализует диагностику данного паттерна 64-битных ошибок, так как

этот процесс не удается формализовать (составить диагностическое правило). Можно только

порекомендовать внимательно просмотреть все участки кода, отвечающие за чтения и запись

данных, а также за передачу их в другие процессы, например посредством технологии COM.

Мы также будем рады, если кто-то из читателей предложит практические шаги, как хотя бы

частично выявлять ошибки описанного типа.

Авторы курса: Андрей Карпов ([email protected]), Евгений Рыжков ([email protected]).

Правообладателем курса "Уроки разработки 64-битных приложений на языке Си/Си++"

является ООО "Системы программной верификации". Компания занимается разработкой

программного обеспечения в области анализа исходного кода программ. Сайт компании:

http://www.viva64.com.

Контактная информация: e-mail: [email protected], 300027, г. Тула, а/я 1800.