Обучающие курсы:

Обучение профессии "Разработчик C#" + стажировка в Mail.ru
Обучение профессии "Разработчик Python" + трудоустройство
Обучение профессии "Веб-разработчик" + стажировка в Mail.ru


Главная страница
Библиотека (скачать книги)
Скачать софт
Введение в программирование
Стандарты для C++
Уроки по C#
Уроки по Python
HTML
Веб-дизайн
Ассемблер в среде Windows
ActiveX
Javascript
Общее о Линукс
Линукс - подробно
Линукс - новое
Delphi
Паскаль для начинающих
Турбопаскаль
Новости
Партнеры
Наши предложения
Архив новостей





У этих двух дизассемблированных фрагментов кода есть общие черты. Если
вы заметили, С++-варианты программ для работы с переменными активно
Встроенный ассемблер языков высокого уровня: принципы использования 517
используют основную память и значительно реже — регистры процессора.
Ничего плохого в этом нет, однако это ведет к избыточности программного
кода и замедлению быстродействия программы в целом. Это незаметно при
небольших объемах вычислений и сравнительно небольших объемах данных,
подверженных обработке. Однако при больших размерах тех же массивов
данных снижение производительности станет заметным.

Например, обмен значений двух элементов массива в реализации на языке
С++:
itmp = il[cnt];
il[cnt] = il[cnt+1];
il[cnt+1] = itmp;
представлен следующим эквивалентом ассемблерного кода:
mov еах,dword ptr [cnt]
mov ecx,dword ptr il[eax*4]
mov dword ptr [itmp],ecx
mov eax,dword ptr [cnt]
mov ecx,dword ptr [cnt]
mov edx,dword ptr [ebp+ecx*4-44h]
mov dword ptr il[eax*4],edx
mov eax,dword ptr [cnt]
mov ecx,dword ptr [itmp]
mov dword ptr [ebp+eax*4-44h],ecx
В то же время, используя комбинацию команд ассемблера:
mov EAX, [EDI]
xchg ЕАХ, [EDI+4]
mov [EDI], ЕАХ
можно добиться повышения производительности в программе поиска максимума.
В этом случае значения переменных хранятся в регистрах, и вычисления
выполняются очень быстро, т. к. значительно уменьшен обмен данными
по системной шине.
То же самое относится и к оптимизации циклов. Объективно заставить
компилятор С + + сгенерировать программный код с максимальным использованием
регистров вместо памяти очень трудно, а во многих случаях невозможно. Хорошо спроектированные на ассемблере циклические вычисления выполняются существенно быстрее и требуют меньшего числа команд.

Рассмотрим, как работает цикл for в программе сортировки. Оператор:
for (int cnt = 0; cnt < tSize_il; cnt++)
распадается на несколько команд ассемблера. Дизассемблированный код
этого оператора модифицируем так, чтобы он воспринимался легче. Для
этого уберем ссылки на адреса физической памяти в командах переходов и
в соответствующих местах заменим их метками. Модифицированный код
будет выглядеть так:
mov dword ptr [cnt], 0
jmp L2
LI:
mov eax,dword ptr [cnt]
add eax,1
mov dword ptr [cnt], eax
L2:
mov eax,dword ptr [cnt]
cmp eax,dword ptr [tSize_il]
jge <адрес>
\
< операторы цикла >
jmp LI


Нельзя сказать, что этот код неоптимален. Если бы вы имели в своем распоряжении только регистры процессора EAX, EDX И ЕСХ, ТО для организации цикла for использовали бы, скорее всего, тот же самый алгоритм. В силу этих ограничений пришлось бы хранить переменные циклов в памяти, и каждый раз (как в этом фрагменте кода) извлекать их для очередной итерации. Если использовать ассемблер, то реализация оператора for при помощи стандартного алгоритма с использованием регистра ЕСХ:
mov ЕСХ, dword ptr isize
loop next
выполняется быстрее.

Как видите, применение языка ассемблер способно решить многие проблемы оптимизации программы, но только если вы хорошо представляете себе, что оптимизировать и как. Это касается не только С + + .NET, Delphi 7, но и других компиляторов.
Еще один важный момент. Современные компиляторы очень мало используют возможности новых архитектур процессоров и их систем команд. Это очень обширная тема, которая требует отдельного обсуждения, но здесь кроются большие резервы для программиста.

Встроенный ассемблер можно с успехом применить и при обработке строк.
Несмотря на то, что среда разработки С + + .NET имеет мощные процедуры обработки строк, использование ассемблера оказывается эффективным и здесь. Дело в том, что часто требуется специфичная обработка строковых переменных, и реализация такой обработки стандартными процедурами оказывается весьма громоздкой и медленной. Вначале рассмотрим наиболее широко используемые типы строк и методы их конвертации.
Как и во всех языках высокого уровня, в С + + .NET широко используются строки с завершающим нулем. Для манипуляции с такими строками в этой среде программирования разработано много самых разнообразных функций. Оптимизация обработки таких строк при помощи ассемблерных процедур была рассмотрена нами в главе 3.

Однако в С++ .NET используются и другие типы строк. Сложность манипуляций со строками с завершающим нулем привела разработчиков Microsoft к необходимости создания класса cstring. Этот класс стал весьма популярным среди программистов. Строка типа c s t r i n g представляет собой последовательность символов переменной длины. Символы строки могут быть как 16-битовые (кодировка UNICODE), так и 8-битовые (кодировка ANSI). Для манипуляции со строками используются методы и свойства класса cstring. Этот класс имеет мощные функции для работы со строками, превосходящие по своим возможностям некоторые стандартные функции языка С++, такие как strcat ИЛИ strcopy.
Для инициализации c s t r i n g объекта можно использовать оператор c s t r i n g : CString s = "Это строка типа CString";
Можно присвоить значение одного объекта cstring другому:
CString si = "Это тестовая строка";
CString s2 = si;

При такой операции содержимое si копируется в s2. Для конкатенации двух и более строк можно использовать операторы " + " или "+=":
CString si = "Строка 1";
CString s2 = "Строкой 2";
si += " объединяется ";
CString sres= si + "со " + s2;

В результате выполнения этой последовательности получим результирующую строку:
Строка 1 объединяется со Строкой 2
Чтобы манипулировать с отдельными элементами строки cstring, можно использовать функции GetAt и setAt этого класса. Первый элемент строки всегда имеет индекс 0. Например, чтобы получить символ строки si с индексом 3, имеющей значение "СТРОКА 1", можно выполнить следующий оператор:
si.GetAt(3)

Такого же результата можно добиться, используя оператор " [ ] " . Тогда доступ к элементу строки будет выглядеть так же, как и к элементу массива:
sl[3]
Результатом операции будет символ "О". Чтобы поместить в позицию с индексом 5 (6-й элемент) этой же строки символ " и " , необходимо выполнить оператор:
sl.SetAt(5, 'И')

Самой мощной функцией класса cstring является функция Format. Она позволяет преобразовать данные других типов в текст и напоминает стандартные функции sprintf и wsprintf. В предыдущих примерах мы применяли эту функцию для вывода элементов массива в поле редактирования Edit. Приведу небольшой фрагмент программного кода:
for (int cnt = 0; cnt < size il; cnt++)
{
si.Format("%d", il[cnt]);
s_Src = s_Src + " 11 + si;
};

Этот код используется для вывода элементов целочисленного массива Ив поле редактирования Edit. Элемент управления Edit имеет тип cstring, т. к. связан с переменной s_Src типа cstring. Здесь же присутствует вспомогательная переменная si, имеющая такой же тип, которую мы используем для преобразования целочисленного элемента массива в строковый тип.
Оператор:
s_Src = s_Src + " " + si;
нам знаком и применяется для вывода преобразованных элементов массива на экран.

Как видите, класс cstring во многом упрощает работу со строками (мы рассмотрели только малую часть его возможностей!). Каким же образом можно манипулировать объектами cstring, используя встроенный ассемблер?
Лучше всего продемонстрировать это на примере. Рассмотрим следующую задачу: требуется в строке типа c s t r i n g заменить все символы пробела символами " + " и вывести результат преобразования на экран.
Для решения задачи разработаем приложение на основе диалогового окна и разместим на нем три элемента Edit, кнопку Button и три метки статического текста Label. Поставим в соответствие элементу Editl переменную si типа cstring, элементу Edit2 — переменную s2 типа c s t r i n g и, наконец, элементу Edit3 — переменную lengthsi целого типа.
В поле редактирования Editl будет вводиться исходная строка с пробелами, в поле Edit2 будет выведен результат замены пробелов на символы " + " , а в поле Edit3 будет отображен размер строки.
Вначале рассмотрим фрагмент программного кода для обработки строки, написанный на С + + .NET (листинг 6.48).


 
 
 

Библиотека программиста. 2009.
Администратор: admin@programmer-lib.ru