Карта сайта Хакер в RSS Энциклопедия Хакера PDA версия сайта Почтовые рассылки Хакера    Хакер в Twitter
Журналы Новости Форум Видео Life Xakep Live (блоги)
Bugtrack Статьи Блог Поиск English
Исполнители желаний: обзор конструкторов популярных Linux дистрибутивов ИСПОЛНИТЕЛИ ЖЕЛАНИЙ: ОБЗОР КОНСТРУКТОРОВ ПОПУЛЯРНЫХ LINUX ДИСТРИБУТИВОВ
02.09.2010

Практически для каждого популярного дистрибутива можно найти удобное средство для создания респина: будь то веб или локальное приложение...
Ученье – свет и высокая зарплата: обзор программных эмуляторов сетевого оборудования Cisco Systems и Juniper Networks УЧЕНЬЕ – СВЕТ И ВЫСОКАЯ ЗАРПЛАТА: ОБЗОР ПРОГРАММНЫХ ЭМУЛЯТОРОВ СЕТЕВОГО ОБОРУДОВАНИЯ CISCO SYSTEMS И JUNIPER NETWORKS
01.09.2010

Чтобы научиться работать с "серьезным" сетевым оборудованием, совсем необязательно иметь тугой кошелек. Можно воспользоваться специальными эмуляторами, полностью имитирующими нужную среду, а то и целые сети...

Упаковка сложных типов данных в Delphi

В этой статье я хотел бы рассказать и показать особенности использования "уплотнения сложных типов данных" в Delphi.

Все когда-нибудь имели дело с записями. Записи используются во многих случаях – для создания файловых справочников, удобной группировки и представления данных, в системном программировании и т.д. Например, открыв файл Windows.pas (стандартный модуль, подключается в разделе uses), можно найти что-то типа такого описания:

_POINTL = packed record
x: Longint;
y: Longint;
end;

или

TISHMisc = packed record
case Integer of //Здесь используется запись с вариантами
0: (PhysicalAddress: DWORD);
1: (VirtualSize: DWORD);
end;

Что же здесь обозначает ключевое слово packed? Слово Packed говорит Delphi минимизировать память. Так что же получается, без этого слова у нас структура занимает памяти больше?

Вот пример записи:

TRecord = Record
pole1 : byte;
pole2 : string[4];
pole3 : integer;
pole4 : Int64;
end;

Давайте подсчитаем ее размер: pole1 – 1 байт, pole2 – 5 байт (надеюсь, не забыли 4 байта под символы и 1 под размер), pole3 – 4 байта, pole4 – 8 байт. Если их сложить получиться 18 байт. Давайте проверим:

size1 := sizeof(TRecord);
ShowMessage(‘Размер обычной записи = ’+IntToStr(size1));

Результат: 24.

Удивлены? А теперь добавьте слово packed перед словом Record… Размер 18 как и подсчитали ранее. Так куда же у нас пропали целые 6 байт?! А если у нас будет массив из 10 000 000 таких записей, например в каком-нибудь справочнике, мы потеряем около 57 Мегабайт?

Давайте разберемся, почему так происходит. Для этого я использовал встроенный дизассемблер в Delphi. На форму кидаем кнопку и на обработчик нажатия пишем:

procedure TForm1.Button1Click(Sender: TObject);
type
// обычная запись
TRecord = Record
pole1 : byte;
pole2 : string[4];
pole3 : integer;
pole4 : Int64;
end;
// упакованная записи
TPackedRecord = Packed record
pole1 : byte;
pole2 : string[4];
pole3 : integer;
pole4 : Int64;
end;

var
Rec : TRecord;
packedRec : TPackedRecord;
size1 : integer;
begin
ShowMessageFmt('Adress = %P',[Addr(Rec)]); //Вывод адреса нашей записи
size1 := sizeof(Rec); //Узнаем размер
// присваиваем некоторые данные нашей записи
Rec.pole1 := $FF;
Rec.pole2 :='hack';
Rec.pole3 := $AAAAAAAA;
Rec.pole4 := $1122334455667788;
ShowMessage('Размер структуры = ' + IntToStr(size1)); //выводим размер
end;

Функцию ShowMessageFmt используем для того, чтобы вывести адрес нашей структуры. Обычный ShowMessage не поможет, т.к. нам надо вывести указатель (тип Pointer). Этот адрес меняется, так что у вас может быть другой. Функция Addr – это получение адреса, возвращаемый тип Pointer. Вот ее результат:

Запомним этот адрес. Теперь поставим breakpoint на последнем ShowMessage – нажмем F5 на этой сроке.

Теперь запустим. Программа выдаст сообщение с адресом, а затем остановиться на предпоследней строке. Нажимаем Ctrl + Alt + C. Появится окно дизассемблера. Щелкаем правой кнопкой мыши по левой-нижней области (dump памяти) и выбираем "Идти к адресу".

Вводим наш адрес записи (например так: $0012F568), который получили с помощью ShowMessageFmt, и попадаем на адрес начала нашей структуры.

Помним, что pole1 мы присвоили значения $FF (т.е. =255), pole2 =’hack’, pole3 = $AAAAAAAA (4 байта, т.е. =2863311530) и т.д. Посмотрим на рисунок, на нем я отобразил структуру байтов и как они расположены в памяти.

Как видим, после данных pole2 идут байты выравнивания, которые выравнивают границу памяти до 8 байт. И поэтому Pole3 начинается с адреса кратному 8. То же самое видим и с Pole4 – сначала выравнивается граница (байты 0E 00 00 00), а затем идут сами данные (хочу заметить, что в памяти данные хранятся в обратном порядке, что видно в Pole4).

А теперь проверим упакованную запись. Переменную Rec заменяем в коде на packedRec, т.е. используем packed record. И проделываем все то же самое:

Здесь видим, что никаких байт выравнивания нет, а все данные (поля) расположены друг за другом – упакованы.

Возможно возник вопрос: почему в первом примере данные выравнивались по границе 8 байт? Все дело в настройках компилятора. Если вы откроете Project – Option – Compiler (опции компилятора), то там будет списочек Record field alignment, в котором можно выбрать нужное выравнивание (8,4,2 или 1 байт). Не забываем перекомпоновать проект после изменений. Кстати выравнивание по 1 байту и есть упаковка данных.

Второй вопрос: почему же всегда не упаковывать данные? К сожалению, упаковка данных имеет не только плюсы, но и минусы. Так, например, не выравнивая границу мы увеличиваем время доступа к полям. Поэтому использовать упаковку надо с умом.

Кстати, в том же файле Windows.pas можно найти не только упаковка записей, но и массивов, вот пример:

CprMask: packed array[0..3] of DWORD;

Попробуйте сами проанализировать упаковку этого массива.



Теги: Delphi , программирование





СЛЕДУЮЩИЕ СТАТЬИ
Брутим дедики по-новому: свежий подход к программированию RDP-брутфорсеров
Подглядываем через веб-камеру: учимся использовать встроенную веб-камеру в своих целях
$1000 на Android: зарабатываем на приложениях для мобильной платформы от Google
Модифицируем подписанные библиотеки в .NET
Проникаем в Extended SMRAM или еще раз о потусторонней памяти №2
.NET Remoting: программим системы распределенных grid-вычислений
Реал-тайм в Вебе: технология Comet для построения быстрых веб-приложений
Мобильные шаровары: как разрабатывать и продавать программы для Symbian
Проникаем в Extended SMRAM или еще раз о потусторонней памяти №1
Взрослые игры в электронной песочнице: персональный Sandbox на C#
ПРЕДЫДУЩИЕ СТАТЬИ
KIS 2010: версия новая, баги старые
Windows 7 для разработчика: технологические нововведения в новой ОСи
Global Positioning Trojan: следим за местоположением жертв продвинутого телефона
Термальная угроза: мифы и реальность №2
Разработка виджетов в Windows Mobile 6.5
Конь в яблоках: пишем троян для Apple iPhone
Термальная угроза: мифы и реальность №1
Куда податься телефонному кодеру: полный гид по мобильным платформам для программиста
Проникновение в BIOS ROM: осваиваем SPI Flash №2
Проникновение в BIOS ROM: осваиваем SPI Flash №1
ОБСУЖДЕНИЕ СТАТЬИ
Логин:
Пароль:
Регистрации на сервере не требуется, вы можете использовать гостевой доступ.
Если у вас есть форумный логин, вы можете использовать его.
Если нет, то вы можете зарегистрироваться на forum.xakep.ru
Обсуждение этой статьи на forum.xakep.ru
ВСЕ ПОСТЫ ПРОХОДЯТ ПРЕМОДЕРАЦИЮ, не ждите их мгновенного появления в списке комментариев.
Для отправки сообщения введите код, указанный на картинке
Заголовок
Сообщение

Guest Отправлено: 20.10.2009 18:14:10
RE: Упаковка сложных типов данных в Delphi
Отличная статья. Хоть немного научит новичков пользоваться дизассемблером, а то привыкли накидать кнопок в design-time и мнет себя крутыми программистами.
Guest Отправлено: 20.10.2009 22:55:38
RE: Упаковка сложных типов данных в Delphi
побольше таких статей
Guest Отправлено: 20.10.2009 23:39:07
RE: Упаковка сложных типов данных в Delphi
Делфи мёртв. Не тратьте время, учите нормальные языки.
=OutlaW= Отправлено: 21.10.2009 8:01:35
RE: Упаковка сложных типов данных в Delphi
quote:

Делфи мёртв. Не тратьте время, учите нормальные языки.

Кто сказал "мяу"?
Guest Отправлено: 21.10.2009 15:06:16
RE: Упаковка сложных типов данных в Delphi
делфи мертв? скажи это моему преподу по программированию
Guest Отправлено: 21.10.2009 15:14:42
RE: Упаковка сложных типов данных в Delphi
"Делфи мёртв. Не тратьте время, учите нормальные языки." - и что по твоему нормальные языки, а что нет? или мы по моде шагаем?
Для каждых вещей выбирается конкретный язык, это конечно то, что касается профессионалов, а не ньюби как ты.
К тому же он еще не умер, так как каое никаое развитие, но есть.
Давно ли ты видел развитие Perl? это мертвый язык? то-то же
Guest Отправлено: 21.10.2009 15:16:23
RE: Упаковка сложных типов данных в Delphi
"делфи мертв? скажи это моему преподу по программированию" - а при чем тут преподы вообще? ты для преподов будешь писать проги всю жизнь?
Для многих преподов жизнь еще остановилась на турбо паскале.
Guest Отправлено: 21.10.2009 16:37:53
RE: Упаковка сложных типов данных в Delphi
Статья пустяковая, даже новичку который прочел хелп понятно что в record секции выравниваются по 4 байта. Если включить packed. То они выравниваются по количеству данных которые там расположены.
D. Scandal Отправлено: 21.10.2009 17:13:53
RE: Упаковка сложных типов данных в Delphi
И снова унылая возня вокруг Делфи. Задета славянская гордость могущественных делфи-кодеров.
Старый пес ваш давно издох, уважаемые.

Я понимаю, что совсем дохлый он будет только в том случае, когда прекратится его разработка, но он очень болен. Очень.
Страницы: < 1 2 3 4 >






Keywords: zPOSTz zHOMEz, zSOFTz, zHOWz, zINFOz, zYANDEXz z49795z
Для Авторов: edit Lock delete Lock



    Rambler's Top100