Рубрики: КОМПЬЮТЕРНАЯ ЛИТЕРАТУРА

про компютерное железо, документация, языки программирования

Turbo Debugger 3.0 #3-3

КОМПЬЮТЕРНАЯ ЛИТЕРАТУРА

LIB.com.ua [электронная библиотека]: : Turbo Debugger 3.0 #3-3

і і Вы можете использовать этот параметр, і
і і чтобы предотвратить загрузку данной і
і і информации для библиотеки, которая не і
і і требует отладки. По умолчанию будет і
і і установлено значение Yes (Да). і
і і і
і Debug startup і Задает, нужно ли отлаживать код начальной і
і (No/Yes) і загрузки DLL. По умолчанию устанавливаетсяі
і і No (Нет). і
і і і
і DLL Name і Введите имя DLL, отсутствующей в списке і
і і DLLs & Programs (DDL и программы), чтобы і
і і добавить библиотеку в этот список. і
і і Добавление DLL в список позволит затем і
і і использовать для этой DLL одну из трех і
і і предыдущих команд. При необходимости можноі
і і задать полный маршрут. і
і і і
і Add DLL і Добавить DLL в текущий блок текстового і
і і ввода в список DLLs & Programs. і
АДДДДДДДДДДДДДДДДДДДБДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДЩ

Добавление DLL в список DLLs & Programs
ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

Прежде чем вы сможете установить отладочные параметры, необ-
ходимость отлаживать начальный код загрузки DLL или загружать
таблицу имен идентификаторов и исходный код DLL, эта DLL должна
быть внесена в список DLL & Programs (DLL и программы). Библиоте-
ка DLL, к которой обращается ваша программа, может и не быть в
этом списке, поскольку сразу после загрузки программы TDW знает
только о DLL, компонуемых с начальным кодом загрузки прикладной
программы. Программа может также запустить DLL явно, при помощи
команды LOADLIBRARY. TDW не знает об этом до вызова LOADLIBRARY.

TDeb 3.0 #3-3 = 38 =

Существует два различных типа кода начальной загрузки, упо-
минаемые в данном разделе: начальный код загрузки вашей приклад-
ной программы и начальный код загрузки DLL. Некоторые динамически
компонуемые библиотеки DLL запускаются начальным кодом загрузки
вашей прикладной программы. Когда ваша программа запускает DLL,
выполняется начальный код загрузки DLL.

Если вы хотите добавить DLL в список DLLs & Programs, вызо-
вите диалоговое окно Load Modules or DLLs (Загрузка модулей или
DDL) (нажмите клавишу F3 или используйте команду ViewіModules
(ОбзоріМодули)), перейдите к блоку текстового ввода DLL Name (имя
DLL), введите имя DLL (если необходимо, введите полный маршрут),
и активизируйте «кнопку» Add DLL, чтобы добавить это имя в спи-
сок.

TDeb 3.0 #3-3 = 39 =

Установка параметров отладки для DLL
ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

Если вы хотите установить для DLL точки останова или слеже-
ния, или еще какие-либо параметры отладки, вызовите окно диалога
Load Modules or DLLs (Загрузка модулей или DDL) (нажмите клавишу
F3 или выберите команду ViewіModules), найдите DLL в списке DLLs
& Programs, выделите его и затем используйте команду Symbol Load
(Загрузка идентификатора), чтобы получить окно Module с этой биб-
лиотекой DLL в нем. В окне Module (Модуль) вы можете выполнить с
DLL интересующие вас операции.

Управление загрузкой TDW таблиц имен идентификаторов DLL
ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

По умолчанию TDW загружает таблицу имен идентификаторов и
исходный код для каждой DLL, к которой обращается ваша прикладная
программа, но только если DLL имеет совместимую таблицу имен
идентификаторов. DLL имеет таблицу имен идентификаторов, совмес-
тимую с TDW. При компиляции с включенной информации для отладки и
с помощью компилятора Турбо Паскаля для Windows DLL содержит таб-
лицу идентификаторов, совместимую с TDW.

Поскольку загрузка отладочной информации для DLL и затем
загрузка отладочной информации для прикладной программы после то-
го, как DLL отработает, занимает время, вам может понадобиться
отменить стандартные действия для DLL, которую вы не хотите отла-
живать. Чтобы TDW не загружал таблицу имен идентификаторов для
DLL, вызовите окно диалога Load Modules or DLLs (нажатием клавиши
F3 или командой ViewіModules), найдите имя этой DLL в списке DLLs
& Programs, выделите его и активизируйте «кнопку» Load Symbols
(Загрузка идентификаторов) со значением No (Нет).

Отладка начального кода загрузки DLL
ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

По умолчанию TDW не отлаживает начальный код загрузки DLL, а
только загружает таблицу имен идентификаторов DLL, когда ваша
прикладная программа вызывает точку входа этой DLL. Затем TDW вы-
зывает окно Module (Модуль) или CPU (ЦП) с маркером текущей стро-
ки на начале подпрограммы DLL, вызванной прикладной программой.

Отладчик TDW будет отлаживать начальный код загрузки DLL,
если вы явно зададите это. Вы можете использовать TDW для отладки
любого из двух типов начального кода загрузки DLL.

Какого рода начальный код загрузки вы отлаживаете

— Код инициализации, непосредственно после LibMain (по умол-
чанию).

— Ассемблерный код, скомпонованный с DLL, выполняющий на-
чальную загрузку и содержит эмулированные математические

TDeb 3.0 #3-3 = 40 =

пакеты для используемой DLL модели памяти (выбираемой при
запуске TDW параметром командной строки -l).

После того, как вы задали отладку начального кода загрузки
одной или более DLL вашей прикладной программы, TDW загружает
таблицу имен идентификаторов для каждой библиотеки DLL либо когда
начальный код загрузки вашей прикладной программы запускает эту
DLL, либо когда прикладная программа явно делает вызов
LOADLIBRARY.

Загружена ли уже ваша прикладная программа?

Если вы пытаетесь загрузить прикладную программу, а уже за-
тем задать отладку начального кода загрузки, отладчик TDW может
повести себя иначе, чем вы ожидали, так как некоторые или все
библиотеки DLL могут уже оказаться загруженными. Следовательно,
задавать отладку начального кода нужно:

— Установив отладку для DLL до загрузки вашей прикладной
программы.

— Загрузив вашу прикладную программу, указав DLL для отладки
начального кода загрузки, а затем перезапустив программу
(Ctrl-F2 или RunіProgram Reset).

Выполнение отладки начального кода загрузки

Учитывая все эти предварительные замечания, используйте для
задания отладки начального кода загрузки для одной или более DLL
и для отладки начального кода загрузки этих библиотек следующие
шаги:

1. Вызовите окно диалога Load Modules or DLL (нажмите F3 или
воспользуйтесь командой ViewіModules (ОбзоріМодули).

2. Найдите DLL в списке DLLs & Programs и выделите ее.

3. Активизируйте «кнопку» Debug Startup (Отладка кода иници-
алиазции) значением Yes (Да).

4. Повторите шаги 2 и 3, пока вы не зададите отладку началь-
ного кода загрузки для всех библиотек DLL, для которых
это необходимо.

5. Если нужная вам DLL находится не в списке или в списке
нет DLL (поскольку вы еще не загрузили прикладную прог-
рамму), используйте поле текстового ввода DLL Name для
ввода каждого имени DLL и добавления его в список при по-
мощи «кнопки» Add DLL (Добавление DLL), а затем выберите
«кнопку» Debug Startup Yes (Отладка начального кода раз-
решена).

6. После того, как вы установили все DLL, для которых вы хо-

TDeb 3.0 #3-3 = 41 =

тите отлаживать начальный код загрузки, следующим шагом
будет либо загрузка при помощи команды FileіLoad
(ФайліЗагрузка) вашей прикладной программы (если вы еще
ее не загрузили), либо перезагрузка программы при помощи
команды RunіProgram Reset (ВыполнениеіСброс программы)
(если вы загрузили ее до того, как задали отладку началь-
ного кода загрузки).

7. Перед выполнением прикладной программы вам следует уста-
новить точки останова, чтобы после выполнения кода на-
чальной загрузки DLL возвращаться в прикладную программу.
Когда в окне Module находится исходный код прикладной
программы, сделайте следующее:

а) установите на первой строке прикладной программы
точку останова;

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

7. Когда ваша прикладная программа запускает каждую из DLL,
отладчик TDW выводит либо LibMain DLL в окне Module (по
умолчанию), либо начало листинга ассемблерного кода на-
чальной загрузки библиотеки в окне CPU (так как TDW запу-
щен с параметром -l).

8. Когда вы закончили отлаживать начальный код загрузки DLL,
нажмите клавишу F9 для того, чтобы выполнить до конца на-
чальный код загрузки и вернуться к прикладной программе.
Если вы задали еще другие библиотеки DLL для отладки на-

Страницы: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43

Turbo Debugger 3.0 #3-3

КОМПЬЮТЕРНАЯ ЛИТЕРАТУРА

LIB.com.ua [электронная библиотека]: : Turbo Debugger 3.0 #3-3

чального кода загрузки, TDW выводит на экран начальный
код для этих библиотек DLL, как только программа запуска-
ет каждую из них.

Не забудьте выполнить до конца начальный код загрузки DLL,
прежде чем перезагрузить текущую прикладную программу или загру-
зить новую. Если вы забудете сделать это, частично выполненный
начальный код DLL может привести к тому, что Windows «зависнет»,
и вам придется перезагружаться.

TDeb 3.0 #3-3 = 42 =

Преобразование описателей памяти в адреса
ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

Windows использует для объектов не адреса памяти, а логичес-
кие номера (описатели) памяти, так как выполняет собственную ор-
ганизацию памяти и может изменить физическое расположение объекта
в памяти. Если вам нужен фактический адрес, соответствующий логи-
ческому номеру, вы можете использовать для этого встроенные имена
Турбо отладчика — lh2fp (для локальных логических номеров) и
gh2fp (для глобальных логических номеров) для обращения по логи-
ческому номеру к адресу памяти.

Вы можете использовать эти имена для приведения типов в TDW,
как для приведения типов указателей в Турбо Паскале обычные ис-
пользуются символические имена. Например, вы можете преобразовать
локальный логический номер hLocalMemory двумя методами:

— Вы можете использовать окно DataіInspect (ДанныеіПроверка)
для вычисления следующего выражения:

(lh2fp) hLocalMemory

— Вы можете использовать команду Type Cast (Приведение типа)
окна Inspector (Проверка) и ввести там lh2fp в качестве
типа.

В любом случае выражение вычисляется для первого символа
блока памяти, на который указывает HLocalMemory.

Вы можете также использовать любой из этих методов для вы-
полнения более сложного приведения типов — например, для двухша-
гового приведения от логического номера к дальнему символьному
указателю на дальний указатель данных в памяти, следующим обра-
зом:

(Mystruct far *) (lh2fp)hLocalMemory

Рекомендации по отладке
ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

Поскольку прикладные программы для Windows являются интерак-
тивными программами, лучший способ отладки состоит в том, чтобы
запустить ее и останавливать в точках останова.

Как первичное средство отладки пошаговое выполнение или
трассировка программы для Windows может оказаться недостаточным,
так как в конце концов вам встретится код, который зациклится в
ожидании сообщения для окна. Для таких случаев вы можете устано-
вить, там где это возможно, точки останова для кода и для сообще-
ний, выполнить программу до такой точки останова, а затем уже пе-
рейти к пошаговому выполнению или трассировке.

При пошаговом режиме в цикле приема сообщения вы можете на-

TDeb 3.0 #3-3 = 43 =

жать комбинацию клавиш Alt-F5, чтобы видеть экран прикладной
программы, но вы не сможете с ней взаимодействовать. Для этого вы
должны нажать клавишу F9 для запуска программы, чтобы видеть окна
программы, однако как быть, если вам нужно попасть обратно в TDW
для трассировки ошибки, которую вы обнаружили, пока использовали
одно из окон вашей программы?

В случае прикладной программы для DOS вы можете нажать Ctrl-
Break, чтобы прервать программу и вернуться к Турбо отладчику,од-
нако в случае Windows эта команда не работает. Однако, и здесь
есть способ прервать программу: нажмите комбинацию клавиш
Ctrl-Alt-SysRq. Попав обратно в TDW, вы можете установить точки
останова для кода и сообщений, задать выражения просмотра, прос-
мотреть все сообщения, зарегистрированные в протоколе, или выпол-
нить любые другие действия по локализации ошибки. Как только вы
будете готовы вернуться в отлаживаемую программу, нажмите клавишу
F9.

Когда ваша программа прервана, нельзя делать следующее:

— Продолжить отладку пошаговым выполнением. Попытка пошаго-
вого выполнения после того, как произошло прерывание, при-
ведет к непредсказуемым результатам, поскольку ваша прог-
рамма могла выполнять код Windows. Обычно в этом случае
Windows завершает как вашу прикладную программу, так и
TDW, выводя сообщение: «Unrecoverable application error»
(«Невосстановимая ошибка прикладной программы»).

— Если ваша прикладная программа выполняла код Windows, не
завершайте выполнение ни прикладной программы, ни отладчи-
ка TDW. Если вы это сделаете, то Windows может сбиться и
«зависнуть», и вам придется перезагружать систему. Если в
этой ситуации вы попытаетесь выйти из программы или пере-
загрузить ее, TDW выведет диалоговое окно с запросом:

Ctrl-Alt-SysRq interrupt. System crash possible. Continue ?
(Прерывание по Ctrl-Alt-SysRq. Возможен сбой системы. Про-
должить?)

TDeb 3.0 #3-3 = 44 =

Сообщения об ошибках TDW
ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

Существует два сообщения об ошибке, возвращаемые исключи-
тельно отладчиком TDW. Кроме того, могут возвращаться и сообщения
об ошибках Турбо отладчика, распространяющиеся и на работу TDW,
например «Symbol not found» в ответ на несуществующее имя оконной
процедуры.

Ctrl-Alt-SysRq interrupt. System crash possible. Continue ?
(Прерывание по Ctrl-Alt-SysRq. Возможен сбой системы. Про-
должить?)

Вы пытались либо выйти из TDW, либо перезагрузить отлаживае-
мую прикладную программу, когда программа была приостановлена в
результате нажатия клавиш Ctrl-Alt-SysRq. Поскольку в момент при-
остановки программы выполнялся код ядра Windows, выход из TDW или
перезагрузка прикладной программы может привести к непредсказуе-
мым результатам (вероятнее всего, к зависанию системы и необходи-
мости ее перезагрузки).

Если это возможно, установите в коде точку останова и снова
запустите программу. Когда ваша программа встретит эту точку ос-
танова и выйдет в TDW, вы можете завершить работу с TDW или пере-
загрузить вашу программу.

Invalid window handle
(Неверный логический номер окна)

Пытаясь установить регистрацию сообщений для окна вашей
программы, вы ввели имя переменной логического номера (описате-
ля), которой не был присвоен логический номер. Пройдите в пошаго-
вом режиме до оператора, где этот логический номер присваивается
переменной, и попробуйте снова ввести это имя.

TDeb 3.0 #3-3 = 45 =

Глава 18. Отладка прикладной программы для Windows
ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

В данной главе описывается отладка стандартной прикладной
программы Windows, написанной без библиотечного класса
ObjectWindow.

Как было сказано в Главе 17, отладка прикладной программы
для Microsoft Windows во многом похожа на отладку программы для
DOS, особенно если речь идет об интерактивной программе для DOS.
Все методы отладки, описанные в Главе 14, «Отладка программы»,
применимы также и для программы для Windows.

Поскольку прикладная программа для Windows использует интер-
фейс прикладных программ для Windows (Application Program
Interface — API), существует множество дополнительных способов
работы с программой. Данная глава не претендует на то, чтобы нау-
чить вас способам безошибочного программирования в Windows. Ее
цель состоит в том, чтобы продемонстрировать средства TDW на при-
мере отладки прикладной программы.

Примеры программ
ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

С отладчиком TDW поставляются три примера программ, и все
они требуют наличия «мыши». Это программы:

— BCWDEMO.EXE, выполняемый файл программы Simple Paint. Эта
программа позволяет строить линии, эллипсы и прямоугольни-
ки тремя цветами и тремя толщинами линии. Она устанавлива-
ется для работы под управлением менеджера программ, и мо-
жет быть вызвана посредством выбора соответствующей
пиктограммы. Вместе с BCWDEMO.EXE также поставляются файлы
исходного текста, BCWDEMO.C, и файл проекта, BCWDEMO.PRJ.

— BCWDEMOA.EXE, выполняемый файл, который содержит все ошиб-
ки. С ним также поставляются файлы исходного текста,
BCWDEMOA.C, и файл проекта, BCWDEMOA.PRJ.

— BCWDEMOB.EXE, выполняемый файл, который содержит все те же
ошибки, что и BCWDEMOA, кроме первой. С ним также постав-
ляются файлы исходного текста, BCWDEMOB.C, и файл проекта,
BCWDEMOB.PRJ.

TDeb 3.0 #3-3 = 46 =

Кроме того, имеется несколько файлов, общих для всех трех
версий программы, а именно:

Страницы: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43

Turbo Debugger 3.0 #3-3

КОМПЬЮТЕРНАЯ ЛИТЕРАТУРА

LIB.com.ua [электронная библиотека]: : Turbo Debugger 3.0 #3-3

— BCWDEMO.DEF, это файл определения модуля.

— BCWDEMO.H, это файл заголовка.

— BCWDEMO.RC, это исходный файл для получения ресурсного
файла.

— BCWDEMO.RES это скомпилированный ресурсный файл.

TDeb 3.0 #3-3 = 47 =

Компиляция и компоновка демонстрационных программ
ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

Вам предоставляется три версии демонстрационной программы,
которые упрощают изучение данной главы. При желании вы можете са-
ми внести изменения в эти программы. С помощью компилятора
Borland C++ вы можете скомпилировать и скомпоновать их в интерак-
тивной среде разработки разработки программ Borland, используя
имеющиеся файлы проекта.

Более подробную информацию о компиляции программ для Windows
с использованием файлов проекта см. в «Руководстве пользователя
для Borland C++.»

Отладка программы BCWDEMOA
ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

Примечание: Прежде чем начать сеанс отладки, вы можете
немного поэкспериментировать с BCWDEMO.EXE, чтобы понять,
что собственно должна делать эта программа.

Первая отлаживаемая программа называется BCWDEMOA. Запустите
Windows, TDW и запустите BCWDEMOA. Когда в окне Module появится
исходный код программы, нажмите клавишу F9 для запуска примера
программы.

На экране появится курсор в виде «песочных часов», который
означает, что программа работает и выполняет некоторые действия.
Обычно курсор в виде часов скоро исчезает, и на его месте появля-
ется курсор в виде стрелки. Если песочные часы не исчезают, зна-
чит, что-то происходит неверно.

Чтобы перейти в TDW для выяснения причин неверной работы,
нажмите клавиши Ctrl-Alt-SysRq, чтобы приостановить выполнение
программы.

Принятие решения о дальнейших действиях
ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

После того, как вы оказались в TDW, следующим шагом вы долж-
ны решить, каким именно образом выяснить, что в программе невер-
но. Обычно если прикладная программа для Windows зависает и не
позволяет судить о ходе ее выполнения, вы перезагружаетесь и на-
чинаете пошаговую отладку подпрограмм инициализации окна. Дойдя
до цикла сообщений, вы можете задать регистрацию сообщений
Windows, можете установить их регистрацию, чтобы затем посмот-
реть, какие сообщения поступают в программу.

Так как исходный экран программы все же был отображен, вы
знаете, что программа дошла до цикла сообщений, поскольку для то-
го, чтобы нарисовать этот экран, она должна была обрабатывать со-
общения Windows. Следовательно, вы можете вместо пошагового вы-
полнения сразу же перейти к регистрации сообщений. Зная, какие

TDeb 3.0 #3-3 = 48 =

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

Завершение BCWDEMOA
ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

В этой точке вы можете задать, какие сообщения вы хотите ре-
гистрировать, и вернуться к программе, нажав клавишу F9, однако
выйдя из программы и снова запустив ее, вы сможете получить более
точную картину происходящего. Поскольку с помощью клавиш Ctrl-Alt
-SysRq вы только приостановили выполнение программы, то выход из
программы в этой точке может привести к зависанию системы (если в
момент приостановки выполнялось ядро Windows). Для завершения
программы выполните следующие шаги:

1. Перезагрузите программу командой RunіProgram Reset
(ВыполнениеіСброс программы) (клавиши Ctrl-F2).

2. После перезагрузки вы получите окно модуля с WinMain. Ес-
ли все так и произошло, вы можете пропустить все дальней-
шие шаги и перейти к разделу «Регистрация сообщений».

3. Если же вы получили окно с сообщением «Ctrl-Alt-SysRq
Interrupt. System Crash possible. Continue?» («Прерывание
по Ctrl-Alt-SysRq. Возможен сбой системы. Продолжить?»,
выберите No (Нет), чтобы отменить выход из программы. В
этом случае выход должен выполняться в точке останова по
сообщению.

4. Вызовите команду ViewіWindows Messages, чтобы вызвать
окно Windows Message (Сообщения Windows).

5. Курсор находится в верхней левой области, Window
Selection (Выбор окна). Вызовите локальное меню (нажав
Alt-F10) и в нем выберите команду Add (Добавление).

6. Введите имя подпрограммы, в которой обрабатываются сооб-
щения для данного окна. В этой программе имеется только
одно окно, и следовательно, только одна подпрограмма об-
работки сообщений, WndProc.

7. Нажмите клавишу Enter, чтобы подтвердить ввод.

8. При помощи клавиши Tab или «мыши» перейдите в правую об-
ласть, Message Class (Класс сообщений), затем вызовите
локальное меню этой области и выберите там команду Add
(Добавление).

TDeb 3.0 #3-3 = 49 =

9. В окне диалога Set Message Filter (Установка фильтра со-
общений) выберите All Messages (Все сообщения) в качестве
класса сообщений и Break (Прерывание) в качестве дейс-
твия, и нажмите Enter, чтобы добавить этот класс сообще-
ний. TDW затем прекратит выполнение программы на первом
же сообщении.

10. Для возобновления работы программы нажмите F9. На следую-
щем же сообщении программа прервется, и управление возв-
ратится в TDW.

11. В TDW установите курсор на WinMain и при помощи команды
RunіProgram Reset (ВыполнениеіСброс программы) перезагру-
зите программу. Затем вы сможете продолжить отладку.

TDeb 3.0 #3-3 = 50 =

Регистрация сообщений
ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

На этот раз, прежде чем запустить программу, вы зададите TDW
регистрацию всех сообщений. Откройте окно Windows Messages (Сооб-
щения Windows) при помощи команды ViewіWindows messages (Об-
зоріСообщения Windows) и добавьте в верхней левой области
WndProc. В правой верхней области должна появиться надпись Log
all messages (Регистрация всех сообщений). Это именно то, что вам
нужно, и работа с этим окном закончена.

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

1. Перейдите в нижнюю область окна Windows Messages (Сооб-
щения Windows) и вызовите локальное меню.

2. Выберите команду Send To Log Window (Пересылка в окно ре-
гистрации). Если эта установка имеет значение No (Нет),
переключите ее на Yes (Да), нажав клавишу Enter.

3. Перейдите в окно Log (Регистрация), выбрав команду
ViewіLog (ОбзоріРегистрация), и вызовите локальное меню.

4. Выберите команду Open Log File (Открыть файл регистрации)
и нажмите клавишу Enter, чтобы подтвердить имя файла ре-
гистрации (журнала) по умолчанию, BCWDEMOA.LOG.

Теперь вы готовы запустить программу, нажав клавишу F9. Ког-
да появится экран, нажмите клавиши Ctrl-Alt-SysRq, чтобы вернуть-
ся к TDW.

Анализ протокола сообщений
ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

В нижней области окна Windows Messages (Сообщения Windows)
вы увидите множество сообщений WM_PAINT, и вероятно, больше ника-
ких других. Для того, чтобы просмотреть все сообщения, выберите
команду ViewіFile (ОбзоріФайл) и получите список всех файлов в
текущем каталоге. Выберите из этого списка файл BCWDEMOA.LOG,
представляющий собой протокол сообщений.

При этом вы получите достаточно короткий список сообщений
инициализации окна (16 или около этого), за которым следует очень
длинный список сообщений WM_PAINT. причиной является то, что
Windows начала посылать сообщения, чтобы установить исходный эк-
ран, но «застряла» на сообщении WM_PAINT. Данный анализ отражает
то, что вы видели при запуске программы: экран появился, но боль-
ше ничего не происходило.

TDeb 3.0 #3-3 = 51 =

Поиск ошибки
ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

Итак, что делать дальше? Можно начать с просмотра кода, что-
бы найти там тот, участок, который отвечает за обработку

Страницы: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43

Turbo Debugger 3.0 #3-3

КОМПЬЮТЕРНАЯ ЛИТЕРАТУРА

LIB.com.ua [электронная библиотека]: : Turbo Debugger 3.0 #3-3

WM_PAINT. Однако, существует более привлекательная альтернатива,
которая состоит в том, чтобы установить точку останова по сообще-
нию, позволяющую сразу выйти на нужный участок программы, а затем
начать пошаговое выполнение, которое позволит точно выяснить при-
чину ошибки.

Установка точки останова по сообщению также отменит действие
выхода по Ctrl-Alt-SysRq, который делает небезопасным дальнейшее
пошаговое выполнение программы или выход из TDW. Так как сообще-
нием, на котором «застряла» программа, является WM_PAINT, устано-
вите для TDW прерывание по сообщению WM_PAINT и снова запустите
программу, следующим образом:

1. Снова войдите в окно Windows Messages (Сообщения
Windows), перейдите в правую верхнюю область, вызовите
локальное меню и выберите Add (Добавление).

2. Появится блок диалога Set Message Filter (Задание фильтра
сообщений) с уже выбранным значением Single Message (От-
дельное сообщение), а курсор в это время будет находиться
в текстовом поле ввода Single Message Name (Имя отдельно-
го сообщения). Введите WM_PAINT (только заглавными бук-
вами, иначе TDW не сможет найти соответствие), а в ка-
честве действия выберите Break (Прерывание).

3. Для запуска программы нажмите F9.

Программа немедленно прервется, и вы окажитесь на первой
строке WndProc. (Чтобы получить полный обзор кода, вы должны
очистить с экрана окно Windows Messages). Эта подпрограмма состо-
ит из оператора switch для сообщений, специальным образом обраба-
тываемых программой.

Подпрограмма WndProc:

long FAR PASCAL WndProc (HWND hWnd, unsigned Message,
WORD wParam, LONG lParam)
{
switch(Message)
{
case WM_COMMAND:
return DoWMCommand(wParam, hWnd);
case WM_LBUTTONDOWN:
DoLButtonDown(hWnd,lParam);
break;
case WM_LBUTTONUP:
DoLButtonUp(hWnd,lParam);
break;

TDeb 3.0 #3-3 = 52 =

case WM_MOUSEMOVE:
DoMouseMove(hWnd,lParam);
break;
case WM_PAINT:
DoPaint(hWnd);
break;
default:
return DefWindowProc(hWnd,Message,wParam,lParam);
}
return 0;
}

Пошаговое выполнение программы
ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

Для пошагового выполнения программы нужно нажимать клавишу
F7. Маркер текущей строки дойдет до оператора case WM_PAINT, и
наконец до подпрограммы DoPaint.

Подпрограмма DoPaint:

void DoPaint(HWND hWnd)
{
int i,
saveROP;

HDC hdc,
hMemDC;

RECT theRect,
destRect;

HBITMAP the Bitmap;
PAINTSTRUCT ps;

if (CurrentPoint >= 0)
{
hdc = BeginPaint(hWnd,&ps);
/*
* Определить, какая прямоугольная область отмечена
* как недопустимая.
* Если ни один прямоугольник не помечен как
* недопустимый, то экран будет полностью перерисован.
*/

GetUpdateRect(hWnd,&theRect,0);

if (IsRectEmpty(&theRect))
GetClientRect(hWnd,&theRect);
/*
* Создание DC (контекста устройства) и области
* того же размера, что и обновляемый прямоугольник.
*/

TDeb 3.0 #3-3 = 53 =

hMemDC = CreateCompatibleDC(hdc);
theBitmap = CreateCompatibleBitmap(hdc,
theRect.right-theRect.left
theRect.bottom-theRect.top);
SelectObject(hMemDC,theBitmap);

/*
* Стирание memBitmap
*/

BitBlt(hMemDC, 0, 0,
theRect.right-theRect.left
theRect.bottom-theRect.top,
hdc, 0, 0, SCRCOPY);

/*
* Рисование только тех фигур, которые находятся
* внутри обновляемого прямоугольника.
*/

for (i = 0; i = 0)

Затем управление возвращается в цикл сообщений, в котором
программа принимает следующее сообщение, WM_PAINT, и затем снова
уходит на цикл с WndProc и DoPaint. Подпрограмма DoPaint, безус-
ловно, что-то делает не так, и нужно сначала выяснить, что же она
должна делать на самом деле?

TDeb 3.0 #3-3 = 55 =

Анализ DoPaint
ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

Назначение данной подпрограммы состоит либо в рисовании все-
го экрана при первом вызове подпрограммы, либо в перерисовке об-
ласти экрана, текущего прямоугольника, если на экране было
что-либо нарисовано. Чтобы определить, было ли что-нибудь нарисо-
вано, DoPaint проверяет значение переменной Currentpoint, перво-
начально устанавливаемой в -1. (CurrentPoint указывает число на-
рисованных объектов). Если CurrentPoint имеет значение -1, то
есть значение, которое было установлено при запуске и рисовании
исходного экрана, то брать и перерисовывать содержимое текущего
прямоугольника нет необходимости, поэтому все коды внутри опера-
тора if опускается, и происходит возврат, а Windows перерисовыва-
ет все окно.

Если вы будете проверять значение CurrentPoint в окне

Страницы: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43

Turbo Debugger 3.0 #3-3

КОМПЬЮТЕРНАЯ ЛИТЕРАТУРА

LIB.com.ua [электронная библиотека]: : Turbo Debugger 3.0 #3-3

ViewіWatches (ОбзоріПросмотр), то вы увидите, что оно остается
равным -1 при пошаговом прохождении программы. Это так и должно
быть, поскольку нарисовать что-либо вы не имели возможности.

Нахождение ошибки
ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

Теперь, если вы обратитесь к книге Чарльза Петцольда «Прог-
раммирование для Windows» («Charles Petzold, Programming
Windows»), то причина ошибки станет вам ясна. Минимальная реак-
ция, которая нужна Windows в ответ на сообщение WM_PAINT, должна
состоять в вызове BeginPaint, за которым следует EndPaint. Если
эти подпрограммы не вызываются, то Windows не знает, что было по-
лучено сообщение WM_PAINT, и продолжает посылать WM_PAINT прог-
рамме.

Обратите внимание, что вызов BeginPaint находился внутри
оператора if, и подпрограмма при первой прорисовке экрана не вы-
зывалась. Чтобы решить проблему, вы должны вынести оператор с вы-
зовом BeginPaint за пределы условного оператора if.

Как обстоит дело с оператором EndPaint? Он тоже находится
внутри if, вместе с вызовом подпрограммы ReleaseDC, которая осво-
бождает hdc, логический номер (описатель) контекста устройства,
устанавливаемый вызовом BeginPaint. Эти две строки должны нахо-
диться вне конструкции if.

Завершение BCWDEMOA
ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

В BCWDEMOB, второй версии программы, которую вы будете изу-
чать, ошибка, связанная с WM_PAINT, уже исправлена. Прежде чем
загружать эту программу, нужно завершить работу BCWDEMOA, чтобы
освободить используемые ей ресурсы. Поскольку единственная проб-
лема с этой программой состояла в том, что при первом проходе не
выполнялся код внутри оператора if, установка CurrentPointer в

TDeb 3.0 #3-3 = 56 =

ноль приведет к выполнению этого кода, что позволяет нормально
выйти из программы. Для завершения программы выполните следующие
шаги:

1. В окне Windows Messages (Сообщения Windows) уберите имя
оконной процедуры WndProc в левой верхней области, чтобы
программа не была прервана при получении сообщения
WM_PAINT.

2. Нажимайте F7, пока на дисплее не появится следующая стро-
ка:

if (Currentpointer >= 0)

3. Выделите CurrentPoint, затем нажмите клавиши Ctrl-F4,
чтобы перейти к экрану Evaluate/Modify (Вычисление/Моди-
фикация).

4. Выберите Eval (Вычисление).

5. Поместите курсор на поле ввода New Value (Новое значе-
ние), введите 0, а затем выберите Modify (Модификация),
чтобы изменить значение переменной. Теперь при выполнении
программы оператор if при вычислении условия даст значе-
ние True, а BeginPaint и EndPaint будут выполнены при
первом же проходе.

6. Выберите клавишу F9 для выполнения программы.

7. Выберите Quit для выхода из программы. Чтобы эта команда
сработала, вам может понадобиться нажать клавишу, пос-
кольку Windows может отказаться освободить сообщения вво-
да от «мыши» из системной очереди. Нажатие клавиши осво-
бодит из очереди все находящиеся там в текущий момент со-
общения ввода от «мыши».

Отладка BCWDEMOB
ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

Завершив работу программы BCWDEMOA, вы можете загрузить
программу BCWDEMOB. Когда программа появится на экране, нажмите
для ее запуска клавишу F9, и попробуйте немного поработать с
программой.

Если вы нарисовали большое число объектов, и особенно при
интенсивном перемещении «мыши» при нажатой кнопке, вы увидите в
конце-концов, что с программой начинают происходить странные ве-
щи. Сначала вы сможете заметить,что программа стала медленнее ра-
ботать, а затем объекты исчезают или изменяется цвет или толщина
линий, а экраны перемешиваются. И наконец, все зависает, и вам
приходится перезагружаться аппаратным образом.

Наиболее вероятная причина состоит в ошибочном использовании

TDeb 3.0 #3-3 = 57 =

памяти. Чтобы проверить, так ли это, и найти местоположение ошиб-
ки, повторите загрузку Windows, выполните только менеджер прог-

рамм и TDW, если это возможно (чтобы минимизировать использование
памяти), и загрузите BCWDEMOB и TDW снова.

Переключение из программы
ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

Прежде чем продолжить сеанс отладки, может потребоваться ор-
ганизовать отладку таким образом, чтобы не использовать
Ctrl-Alt-SysRq для переключения из перекладной программы в TDW,
поскольку использование данного метода требует осторожности. Ре-
шение состоит в том, чтобы установить единственное сообщение, по
которому должно выполняться прерывание, и которое вы по своему
желанию можете генерировать в программе, и которое обычно само по
себе не появляется.

Так как BCWDEMO — это работающая с «мышью» графическая прог-
рамма, не принимающая графического ввода, то работа с клавиатурой
здесь обычно не нужна. Следовательно, лучше всего организовать
прерывание по сообщению WM_KEYFIRST. После задания этого сообще-
ния в окне ViewіWindows Message (ОбзоріСообщения Windows) прог-
рамма будет прерываться при каждом нажатии клавиши. (Поскольку
программа не реагирует и на нажатие правой кнопки «мыши», для
этой цели можно использовать и сообщение WM_RBUTTONDOWN).

Тестирование программы
ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

Теперь вы можете нажать клавишу F9, чтобы начать выполнение
программы BCWDEMOB. Прежде чем сделать что-либо в программе, про-
верьте, какой процент системной памяти доступен программам для
Windows, переключившись на менеджер программ, выбрав «кнопку»
Help (Справка) и затем выбрав About Program Manager (О менеджере
программ). Появится информационный блок, в котором будет показана
текущая версия Windows, объем свободной памяти и в нижней части —
интересующие вас статистические данные, процентные соотношения
свободной памяти для системных ресурсов.

Теперь вернемся в программа Simple Paint и немного порисуем.
Затем снова перейдем на экран About Program Manager (О менеджере
программ), и вы увидите, что доступная память для системных ре-
сурсов уменьшилась. Если вы и дальше продолжите рисование, то
объем этой памяти будет продолжать уменьшаться до нуля, и вы по-
лучите тот же эффект, что и ранее.

Принятие решения
ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

Что вам известно в данный момент? Прежде всего, программа
явно распределяет глобальную память, так как она в результате
расходует все системные ресурсы, доступные Windows. С этого можно
начать: вы можете перезагрузить программу, воспользоваться средс-

TDeb 3.0 #3-3 = 58 =

твами TDW контроля глобальной памяти для сохранения списка объек-
тов глобальной памяти в файл регистрации (протокол), немного по-
рисовать в Simple Paint и затем снова получить список объектов
глобальной памяти, записав его в другой файл.

Так как Windows за это время, вероятно, перемещала объекты в
памяти, то два полученных списка могут не совпадать. Вы должны
просмотреть каждый объект в списке и сопоставить его с объектами,
имеющими того же владельца в другом списке, чтобы найти несоот-
ветствия.

Поскольку этот метод занимает много времени, то предлагается
он только как упражнение по просмотру глобальной памяти. Метод,
которым вы будете пользоваться фактически, состоит в том, чтобы
просмотреть объекты памяти, выделяемые программой, и проверить,
выполняет ли программа и их освобождение.

Сравнение списков объектов глобальной памяти
ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

Для получения списка объектов глобальной памяти нужно выпол-
нить следующие действия:

1. Перезапустите Windows, чтобы обеспечить очистку глобаль-
ной памяти от любых объектов, выделенных BCWDEMOB. И
опять, избегайте запускать ненужные программы, чтобы
уменьшить число объектов глобальной памяти.

2. Если вы находитесь в TDW и загрузили BCWDEMOB, снова
установите прерывание программы по сообщению WM_KEYFIRST.

3. Нажмите клавишу F9 для запуска программы, а затем нажмите
клавишу для выхода обратно в TDW.

4. Выберите команду ViewіLog (ОбзоріРегистрация) и вызовите
локальное меню.

5. Выберите команду Open LogіFile (Открыть файліРегистра-
ция), введите в появившемся окне диалога имя файла журна-
ла и нажмите клавишу Enter.

6. Снова вызовите локальное меню окна Log (Регистрация), вы-
берите команду Display Windows Info (Вывод информации
Windows), а затем нажмите клавишу Enter, когда появится
окно диалога Windows Information (Информация Windows).
Нажатие Enter принимает установки по умолчанию, задающие
вывод списка объектов глобальной памяти, начиная с верх-
них адресов памяти.

Страницы: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43

Turbo Debugger 3.0 #3-3

КОМПЬЮТЕРНАЯ ЛИТЕРАТУРА

LIB.com.ua [электронная библиотека]: : Turbo Debugger 3.0 #3-3

7. Когда отладчик TDW закончит листинг глобальной памяти,
снова вызовите список объектов глобальной памяти и выбе-
рите команду Close Log File (Закрытие файла регистрации),
чтобы закрыть файл.

TDeb 3.0 #3-3 = 59 =

8. Выберите из локального меню команду Erase Log (Стереть
протокол), чтобы очистить протокол.

9. Нажмите F9, чтобы снова запустить программу, и при помощи
«мыши» проконтролируйте информацию в блоке About Program
Manager. Запомните проценты, приведенные там для систем-
ных ресурсов.

10. Нарисуйте в Simple Paint достаточно, чтобы уменьшить сис-
темные ресурсы на 20-30 процентов.

11. Нажмите клавишу для возврате в TDW и повторите шаги 4-8,
на этот раз с другим именем файла протокола (регистра-
ции).

12. Выйдите из TDW, распечатайте файлы протоколов и сравните
их.

Проделав это, вы отметите следующее:

— Объекты памяти, принадлежащие BCWDEMOB, не увеличились в
размерах.

— Объекты памяти GDI увеличились в размерах.

Первое из этих примечаний подтверждает то, что вы уже знаете
о программе: отлаживаемый код программы BCWDEMOB выделяет гло-
бальную память, а не локальную.

Второе говорит вам нечто новое: BCWDEMOB выделяет объекты
Интерфейса графических устройств (GDI) и не освобождает их.

Нахождение ошибки: функциональный подход
ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

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

Выбор элементов меню
ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

Выбор элементов меню выполняется посредством помещения кур-
сора в меню, нажатия левой кнопки «мыши» и перемещения по меню к
желаемому элементу, выбор которого изменяет цвет, толщину пера
или форму изображения. Изменение любого из этих значений вызывает
посылку сообщения WM_COMMAND в подпрограмму WndProc, которая об-
рабатывает сообщение, вызывая для этого DoWMCommand.

DoWMCommand содержит оператор switch, который сохраняет сде-

TDeb 3.0 #3-3 = 60 =

ланный вами выбор в переменной программы. Эти переменные хранятся
в сегменте данных BCWDEMO и не влияют на глобальную память.

Рисование фигуры
ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

Для того, чтобы нарисовать фигуру, вы устанавливаете курсор
в предназначенную для графического ввода пользователя область ок-
на, удерживая нажатой левую кнопку «мыши» перемещаете курсор в
другую точку и там отпускаете кнопку «мыши». Если вы перемещаете
«мышь» при ненажатой левой кнопке, вы можете заметить, что фигура
по мере перемещения рисуется, стирается и снова рисуется. Остает-
ся она на экране только при отпускании левой кнопки.

Нажатие левой кнопки «мыши»
ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

При нажатии левой кнопки в области пользовательского графи-
ческого ввода Windows посылает сообщение WM_LBUTTONDOWN в
WndProc, что приводит к вызову DoButtonDown. Эта подпрограмма
сохраняет текущую позицию «мыши» (которая далее именуется
меткой) и выполняет установки характеристик пера в структуре
thisShape. Эта структура представляет собой переменную программы
и влияет только на сегмент данных программы BCWDEMO.

Перемещение «мыши»
ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

Когда вы перемещаете «мышь» при нажатой левой кнопке в поль-
зовательской области ввода, Windows посылает WM_MOUSEMOVE (или WM
_MOUSEFIRST, что то же самое) в WndProc, которая вызывает
DoMouseMove. Эта подпрограмма вызывает DrawShape для стирания фи-
гуры от предыдущей позиции «мыши» до исходной, а затем снова —
для рисования фигуры от текущей позиции до метки. Единственное

использование глобальной памяти в DoMouseMove состоит в получении
контекста устройства для текущего окна, который освобождается в
конце подпрограммы вызовом ReleaseDC.

Рисование фигуры (и нахождение позиции ошибки)
ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

Теперь рассмотрим подпрограмму DrawShape, которая дважды вы-
зывается из DoMouseMove. DrawShape запоминает перо, которым рисо-
валась предыдущая фигура, создает новое перо и рисует линию, эл-
липс или прямоугольник. В конце своей работы она восстанавливает
сохраненное на входе перо.

Поскольку перо — это объект интерфейса графических устройств
(GDI), выделяемый в глобальной памяти, подпрограмма DrawShape мо-
жет содержать код, вызывающий проблемы с памятью. Эта подпрограм-
ма вызывает особенное подозрение, так как она вызывается дважды
при каждом перемещении мыши. Если она создает перья и не удаляет
их, то она «съест» память очень скоро.

TDeb 3.0 #3-3 = 61 =

Действительно, недалеко от начала DrawShape выделяет перо
вызовом SelectObject, но не освобождает выделенную ему память вы-
зовом DeleteObject в конце. Чтобы исправить эту ошибку, вы должны
заменить последнюю строку DrawShape следующим кодом:

DeleteObject(SelectObject(hdc,saveObject));

Возможно, найденная ошибка является единственной причиной
проблем с памятью, однако желательно проверить и все остальные
места программы, связанные с рисованием объектов.

Отпускание левой кнопки
ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

При отпускании левой кнопки «мыши» BCWDEMOB рисует фигуру в
последний раз и оставляет ее на экране. Отпускание кнопки застав-
ляет Windows послать сообщение WM_LBUTTONUP в WndProc, которая
вызывает DoLButtonUp. Эта подпрограмма сохраняет текущий прямоу-
гольник из пользовательской области в массив текущей фигуры
thisShape, вызывает InvalidateRect для добавления области в об-
ласть обновления окна, а затем вызывает UpdateWindow, которая по-
сылает сообщение WM_PAINT прямо в главное окно. Эта подпрограмма
не использует глобальную память.

При выходе из DoLButtonUp сообщение WM_PAINT находится в
очереди и готово к обработке в WndProc.

TDeb 3.0 #3-3 = 62 =

Перерисовка экрана
ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

Когда WndProc получает сообщение WM_PAINT, она вызывает
DoPaint для перерисовки соответствующей области экрана (описана
выше в этом разделе). При перерисовке обновляемого прямоугольника
DoPaint вызывает две подпрограммы Windows, влияющие на глобальную
память: CreateCompatibleDC и SelectObject. В конце DoPaint вызы-
ваются DeleteDC и DeleteObject, которые освобождают выделенную в
начале подпрограммы память.

Заключение
ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

Так как вы рассмотрели все подпрограммы, вы можете быть уве-
рены, что ошибка, связанная с памятью, найдена. Этот метод был
выбран потому, что вы недостаточно детально знаете отлаживаемую
программу. Разумеется, в программе, написанной лично вами, вы
нашли бы такую ошибку гораздо быстрее.

Не мешает также и более подробное тестирование программы.
Хорошо зная программу, вы могли бы не искать ошибку в части прог-
раммы, связанной с меню, так как обнаружили бы, что сбой програм-
мы наступает и при одном только перемещении курсора по экрану с
помощью «мыши». Кроме того, обнаружив, что проблема возникает
только при перемещении «мыши» в области пользовательского графи-
ческого ввода при нажатой левой кнопке (это вы могли бы обнару-
жить, нажав кнопку и перемещая курсор до тех пор, пока не прои-
зойдет сбой программы), вы могли бы сразу предположить, что
проблема связана с подпрограммой DoMouseMove и на ней сосредото-
чить свои усилия.

TDeb 3.0 #3-3 = 63 =

Глава 19. Отладка программы, использующей ObjectWindows
ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

Пример объектно-ориентированной программы данной главы был
написан с помощью класса ObjectWindows, который существенно об-
легчает программирование в Windows.

Примерами программ служат программа TDODEMO и TDODEMOB (B
обозначает версию программы с ошибками). Программа TDODEMOB со-
держит несколько ошибок, которые вы выявите при работе с данной
главой.

Перед тем, как продолжить изучение, полезно запустить из
Windows программу TDODEMO и немного поэкспериментировать с ней,

Страницы: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43

Turbo Debugger 3.0 #3-3

КОМПЬЮТЕРНАЯ ЛИТЕРАТУРА

LIB.com.ua [электронная библиотека]: : Turbo Debugger 3.0 #3-3

чтобы получить представление, как она работает. Вы можете исполь-
зовать для запуска TDODEMO.EXE команду FileіRun (ФайліВыполнение)
менеджера программ или добавить ее к программной группе в качест-
ве пиктограммы.

Примечание: При отсутствии файлов .EXE для файлов
TDODEMO и TDODEMOB вам потребуется открыть их файлы проектов
и перекомпилировать эти файлы с включением отладочной инфор-
мации.

О программе
ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

TDODEMOB — это программа, написанная с использованием
ObjectWindows, позволяющая рисовать на экране различными цветами
с помощью «мыши». Когда вы нажимаете левую кнопку «мыши» и пере-
мещаете «мышь», то программа рисует на экране линию. Нажав правую
кнопку «мыши», вы можете очистить окно. Программа TDODEMO имеет
строку меню, которая позволяет вам выбрать один из 4 цветов: Red
(красный), Green (зеленый), Blue (голубой) или Black (черный).

Вы можете рисовать, нажимая кнопку «мыши», перемещая «мышь»
и освобождая кнопку «мыши». Программа легко выполняет эту задачу
с помощью библиотеки ObjectWindows и динамических виртуальных ме-
тодов. Динамический виртуальный метод — это метод с присвоенным
ему числовым идентификатором.

Поскольку Borland C++ определяет имена сообщений Windows,
как числовые константы, вы можете использовать номера сообщений
Windows в качестве идентификатора динамического метода. При этом
ObjectWindows может вызывать данный метод, когда окно, для кото-
рого объявлен метод, получает совпадающее с идентификатором мето-
да сообщение. Если нет метода, идентификатор которого совпадает с
идентификатором метода, ObjectWindows вызывает используемую по
умолчанию процедуру окна.

Например, чтобы создать метод, который отвечает на сообщения
WM_MOUSEMOVE, вы можете определить метод в объекте окна, который
выглядит следующим образом:

TDeb 3.0 #3-3 = 64 =

procedure WMMouseMove(var Msg: TMessage); virtual WM_MOUSE;

Как вы можете видеть, идентификатор WM_MOUSEMOVE можно при-
соединить к процедуре с помощью оператора virtual , который непосредственно следует за описанием процедуры.

Параметры процедуры окна Windows wParam и lParam содержит
тип TMessage. Эти параметры часто содержат дополнительную инфор-
мацию о сообщении, например, где позиционируется «мышь».

В следующих нескольких разделах поясняется, как работает
программа TDODEMOB. В нее преднамеренно внесены ошибки, которые
вы сможете обнаружить позднее. Полезно также запустить Турбо Пас-
каль для Windows и открыть файл TDODEMOB.PAS, после чего вы смо-
жете следовать по коду программы.

Определение оконного типа ScribbleWindow
ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

Тип ScribbleWindow определяется следующим образом:

class ScribbleWindow : public TWindow
{
public:
HDC HandleDC; // вывод содержимого для рисования
BOOL ButtonDown; // флаг левой кнопки
HPEN ThePen; // перо, которое используется для
// рисования цветом

ScribbleWindow(PTWindowObject AParent, LPSTR ATitle);
-ScribbleWindow();
void GetWindowClass(WNDCLASS &AWndClass);

virtual void WMLButtonDown(RTMessage
Msg)=[WN_First+WM_LBUTTONDOWN];
virtual void WMLButtonUp(RTMessage MSG)=(WM_FIRST+
WM_LBUTTONUP);
virtual void WMLMouseMove(RTMessage MSG)=(WM_FIRST+
WM_MOUSEMOVE);
virtual void WMLButtonDown(RTMessage MSG)=(WM_FIRST+
WM_LBUTTONDOWN);
virtual void SelectRedPen(RTMessage Msg)=(CM_FIRST+
CM_RED);
virtual void SelectGreenPen(RTMessage Msg)=(CM_FIRST+
CM_GREEN);
virtual void SelectBluePen(RTMessage Msg)=(CM_FIRST+
CM_BLUE);
virtual void SelectBlackPen(RTMessage Msg)=(CM_FIRST+
CM_BLACK);
virtual void SetupWindow();
};

TDeb 3.0 #3-3 = 65 =

Класс ScribbleWindow определяет определяет объект окна, ко-
торый отвечает на следующий ввод пользователя:

— перемещение «мыши»;

— нажатие и освобождение левой кнопки «мыши»;

— нажатие правой кнопки «мыши»;

— цвет и позицию пера.

Имеются три экземпляра переменных — HandleDC, ThePen и
ButtonDown, которые содержат класс устройства, текущее перо, ко-
торым рисует пользователь, и состояние кнопки «мыши» соответс-
твенно.

TDeb 3.0 #3-3 = 66 =

Конструктор ScribbleWindow
ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

Конструктор ScribbleWindow присоединяет меню к программе и
инициализирует элемент данных ButtonDown значением FALSE, а
ThePen — значением CM_BLACK.

GetWindowClass
ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

Функция-элемент GetWindowClass вызывает стандартную функцию
TWindow CegWindowClass устанавливает окно таким образом, что оно
ведет себя аналогично любому другому окну TWindow, а затем иници-
ализирует пиктограмму программы.

WMRButtonDown
ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

Когда пользователь нажимает в окне ColorScribble правую
кнопку «мыши» и собирается рисовать, окно получает сообщение
WM_LBUTTONDOWN, которое приводит к тому, что ObjectWindows вызы-
вает подпрограмму WMLButtonDown (так как она имеет идентификатор
WM_FIRST+WM_LBUTTONDOWN). Подпрограмм WMLButtonDown перемещает
перо в текущую позицию «мыши» и устанавливает переменную
ButtonDown, чтобы указать, что кнопка нажата, а затем выбирает
ThePen в текущий контекст устройства. В Windows имеются также до-
полнительные вызовы данной функции, о чем будет рассказано ниже.

WMLButtonUp
ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

Когда пользователь заканчивает рисование и освобождает кноп-
ку «мыши», окно получает сообщение WM_LBUTTONUP, которое в свою
очередь приводит к тому, что ObjectWindows вызывает функцию
WMLButtonUp. Программа присваивает переменной ButtonDown значение
False и освобождает класс устройства, связанный с данным окном.

WMRButtonDown
ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

Когда пользователь нажимает правую кнопку «мыши», чтобы
очистить экран, ObjectWindows вызывает функцию WMRButtonDown, ко-
торая, в свою очередь, вызывает функцию Windows UpdateWindow. Вы-
зов данной функции предназначен для очистки окна.

WMMouseMove
ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

Когда пользователь начинает перемещать курсор по окну, окно
получает сообщение WM_MOUSEMOVE, которое приводит к тому, что
ObjectWindows вызывает функцию WMMouseMove. Если пользователь на-
жал левую кнопку «мыши», то программа рисует при каждом перемеще-
нии «мыши» линию. Если пользователь не нажимает кнопку «мыши», то

TDeb 3.0 #3-3 = 67 =

ничего не происходит.

Подпрограммы цвета пера
ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

Имеются также четыре функции, устанавливающие цвет пера,
удаляя текущее перо и создавая новое перо с нужным цветом. Эти
функции отличаются только устанавливаемыми цветами.

TDeb 3.0 #3-3 = 68 =

Создание прикладной программы
ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

Чтобы создать прикладную программу, которая использует окно
окно ColorScribble, необходимо создать класс на основе класса
ObjectWindow в TApplication. Назначение этого класса (класса
CSribbleApplication) состоит в следующем:

— Переопределении функции InitMainWindow, благодаря чему
прикладная программа сможет создавать основное окно со
свойствами окна CSribbleWindows.

— Обеспечении объектного типа MyApp, который используется

Страницы: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43

Turbo Debugger 3.0 #3-3

КОМПЬЮТЕРНАЯ ЛИТЕРАТУРА

LIB.com.ua [электронная библиотека]: : Turbo Debugger 3.0 #3-3

для установки окна и запуска программы.

Примечание: MainWindow, используемое для задания преры-
вания по сообщению окна, которое описывается в данной главе
ниже, является элементом MyApp.

Теперь вы знаете как работает программа и можете начать ее
отлаживать.

Отладка программы
ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

Если вы еще этого не сделали, запустите отладчик TWD под
Windows, загрузите программу TDODEMOB.CPP затем нажмите клавишу
F9 для запуска демонстрационной программы. Вы можете перемещать
«мышь» и даже выбирать команды меню, но когда вы нажимаете кнопку
«мыши» и начинаете перемещать «мышь», вы увидите, что происходит
сбой программы и она возвращает управление в TDW с сообщением об
ошибке «Exception 13» («Исключительная ситуация 13»).

Примечание: TDW выводит сообщение «Exception 13», когда
ваша программа приводит к невосстановимой ошибке.

Выявление первой ошибки
ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

Когда вы нажимаете клавишу Esc и очищаете окно сообщений,
TDW оставляет вас с окне CPU (ЦП). Данное окно выводится, так как
во время сбоя ваша программа выполняет код Windows. Так как вы не
вернулись в окно Module (Модуль), то отсутствует удобный маркер,
который отмечал бы место, в котором обращение вашей программы к
Windows вызвало невосстановимую ошибку.

Перед тем как продолжить, нажмите клавиши Alt-F3, чтобы зак-
рыть окно CPU (в основном вы будете работать в окно Module).

Поиск функции, которая вызывает Windows
ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

Так как сбой в программе происходит при нажатии левой кнопки

TDeb 3.0 #3-3 = 69 =

«мыши», вероятно проблема заключается в функции WMLButtonUp. Од-
нако существует другой метод, который можно использовать для
определения того, где находилась ваша программа — трассировка
стека.

Для выполнения трассировки стека выберите с помощью команды
ViewіStack (ОбзоріСтек) окно Stack (Стек) и прокрутите вниз спи-
сок шестнадцатиричных инструкций, пока вы не дойдете до строки,
указывающей подпрограмму вашей программы (имя подпрограммы вы
увидите в коде ASCII). Эта строка находится в так называемом яд-
ре Windows.

Как можно видеть в окне Stack, подпрограммой, которую нужно
рассмотреть, в самом деле является подпрограмма WMLButtonDown.
Чтобы перейти к данной подпрограмме в окне Module, сначала щелк-
ните в этом окне кнопкой «мыши». Затем нажмите клавиши Ctrl-S,
наберите WMLButtonDowm и нажмите для поиска этой подпрограммы
клавишу Enter. Если вы увидите сообщение «Search expression not
found» («Искомое выражение не найдено»), перейдите к началу файла
и клавиши Ctrl-N, чтобы снова выполнить поиск (в TDW вы можете
выполнять поиск только от текущей позиции курсора до конца фай-
ла). Возможно, перед тем как вы найдете функцию, вам потребуется
несколько раз нажать Ctrl-N.

TDeb 3.0 #3-3 = 70 =

Отладка функции WMLButtonDown
ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

Функция WMLButtonDown воспринимает в качестве параметра пе-
ременную типа RTMessage и выделяет из этого сообщения позицию
«мыши». Затем она вызывает функции Windows MoveTo и SelectObject
для позиционирования пера в окне и выбора текущего инструмента
рисования.

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

При расположении курсора на строке WMLButtonDown перезагру-
зите программу TDODEMOB, нажав клавиши Ctrl-F2, затем нажмите
клавишу F4, чтобы выполнить программу до этой точки. Команда вы
увидите окно ColorScribble, нажмите левую кнопку «мыши», чтобы
программа вернулась в TDW. (Чтобы получить от Windows сообщения
по событию от «мыши», возможно придется нажать клавишу несколько
раз.) На этот раз невосстановимой ошибки не возникает (по крайней
мере пока), поскольку поскольку все, что пока выполнялось, это
вызов Windows функции WMLButtonUp программы TDODEMOB. Отладчик
TDW возвращает вас к первой строке этой функции.

Начните нажимать клавишу F7 для пошагового выполнения прог-
раммы. Когда вы нажмете F7 на вызове MoveTo, то увидите окно со-
общений, в котором выводится «Exeption 13». Вероятно, проблема в
вызове MoveTo.

Отладка MoveTo
ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

Функция MoveTo работает с пером и текущими координатами кур-
сора x и y. Координаты извлекаются из сообщения Msg, которое при-
ходит от Windows. Если программа не извлекает неверную часть это-
го сообщения (а это не так), то с этими параметрами должно быть
все в порядке.

Местом ошибки должен быть HandleDC — контекст описателя уст-
ройства пера.

В этой точке, поскольку вы имеете две невосстановимых ошиб-
ки, наиболее надежным способом будет выход в TDW и закрытие перед
дальнейшей работой Windows.

Исправление ошибки
ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

Если причиной невосстановимой ошибки является HandleDC, то
либо описатель (контекста устройства) установлен неверно, либо не

TDeb 3.0 #3-3 = 71 =

устанавливался вовсе. На самом деле он не устанавливался. Прог-
рамма должна инициализировать контекст дисплея с помощью следую-
щего вызова Windows:

HandleDC = GetDC(HWindow);

В приведенном ниже исходном коде показан метод
WMLButtonDown с добавленным оператором инициализации контекста.

void ScribbleWindow::WMLButtonDown(RTMessage Msg)
{
if ( !ButtonDown )
{
ButtonDown = True; // отметить кнопку «мыши»,
// так что при перемещении «мыши»
// с нажатой кнопкой будет
// рисоваться линия
HandleDC = GetDC(HWindow); // создать контекст вывода
для рисования при нажатой
кнопке «мыши» }
MoveTo(HandleDC, Msg.LP.Lo, Msg.LP.Hi);
// переместить точку рисования
// в точку нажатия кнопки «мыши»
SelectObject(HandleDC, ThePen);
// выбрать перо для контекста
// устройства
}
}

TDeb 3.0 #3-3 = 72 =

Проверка исправлений
ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

В Borland C++ добавьте в ScribbleWindow::WMLButtonUp опера-
тор инициализации контекста. Далее скомпилируйте проект с включе-
нием отладочной информации (выбрав команду (CompileіBuild All)
(КомпиляторіПолное построение)).

Поскольку в нашем случае имеются другие ошибки, снова загру-
зите в TDW программу, затем при выводе окна Module нажмите клави-
шу F9.

Теперь, если вы рисуете с помощью пера, то линия рисуется
назначенным по умолчанию цветом — черным.Попробуйте рисовать раз-
личными цветами, выбирая из меню цвет пера. Красный, зеленый и
голубой будут работать прекрасно, но когда вы попытаетесь изме-
нить цвет обратно на черный, то цвет пера не изменится. Похоже,
вы нашли другую ошибку.

Поиск ошибки назначения цвета пера
ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

Наиболее вероятным местом этой ошибки является функция
SCribbleWindow, который создает цвет пера SelectBlackPen. Выйдите
из ColorScribble, затем для сброса программы нажмите клавиши
CtrlF2. Установите точку останова на открывающей фигурной скобке
функции CScribbleWindow::SelecrBlackPen. Затем запустите програм-
му и выберите команду PenіBlack. (Чтобы получить сообщение от
Windows, возможно придется нажать клавишу.) Отладчик TDW должен
остановить выполнение на точке останова. Поскольку этого не про-
исходит, здесь что-то неверно.

Вероятно, функция SelectBlackPen никогда не вызывается. Пос-
кольку данная подпрограмма работает на основе динамически диспет-
черизуемой виртуальной таблице, возможно что-то не так с ее иден-
тификатором.

Установка точки останова по сообщению окна
ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

Страницы: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43

Turbo C++ Version 1.0 Programmer’s Guide

КОМПЬЮТЕРНАЯ ЛИТЕРАТУРА

LIB.com.ua [электронная библиотека]: : TURBO C++ Version 1.0 Programmer’s Guide

— 43 —

Методы стандартных арифметических преобразований Таблица 1.15
————————————————————
Тип Преобразование вМетод
————————————————————
char intРасширение нулем или знаком
(в зависимости от умолчания
для типа char)

unsigned char intЗаполнение старшего байта
нулем (всегда)

signed char intРасширение знаком (всегда)

short intТо же значение

unsigned short unsigned int То же значение

enum intТо же значение
————————————————————

Специальные преобразования типов char, int и enum

Обсуждаемые в данном разделе преобразования специфичны
для Turbo C++.

Присваивание объекта типа signed char (например,пере-
менной) интегральномуобъекту вызывает автоматическое расши-
рение знаком. Объекты типа signed char используетрасширение
знаком всегда; объекты типаunsigned charпри преобразовании
вint всегда устанавливают старший байт в ноль.

Преобразование более длинных интегральных типов к более
коротким типам ведет к усечению старших битов, оставляя
младшие без изменения. Преобразование более короткого интег-
рального типа к более длинному либо расширяет лишние биты
нового значения знаком, либо заполняет их нулем, в зависи-
мости от того, является ли более короткий тип signed или
unsigned, соответственно.

Инициализация

Инициализаторы устанавливают исходное значение,хранимое
в объекте (переменные,массивы, структуры, и т.д.). Если вы
не инициализируете объект, и он имеет статическую продолжи-
тельность существования, то он будет инициализирован по
умолчанию, следующим образом:

— нулем, если это объект арифметического типа
— null, если что указатель

В случае автоматического распределения памяти исходное
значение динамической локальной переменной непредсказуемо.

Синтаксис инициализаторов следующий:
инициализатор
= выражение
= (*список-инициализаторов*)*)
(список выражений)

список-инициализаторов
выражение
список-инициализаторов, выражение
(*список-инициализаторов*)*)

Ниже приводятся правила, управляющие инициализаторами:

— 44 —

1. Число инициализаторов в списке инициализаторов не
может превышать число инициализируемых объектов.

2. Инициализируемый элемент должен быть типа объекта
или массивом неизвестной размерности.

3. Все выражения должны являться константами, если они
находятся в одном из следующих мест:

а. в инициализаторе объекта, имеющего статическую дли-
тельность (в Turbo C++ не требуется)

b. в списке инициализаторов для массива, структуры или
объединения (также допустимы выражения с использованием
sizeof)

4. Если объявление идентификатора имеет контекст блока,
и идентификатор имеет внешнюю или внутреннюю компоновку,
объявление не может иметь инициализатор для идентификатора.

5. Если во взятом в фигурные скобки списке инициализа-
торов меньше, чем элементов структуры, то оставшаяся часть
структуры неявно инициализируется таким же образом, как и
объекты со статической продолжительностью существования в

памяти.

Скалярные типы инициализируются в одномвыражении, кото-
рое опционально можно заключить в фигурные скобки. Исходное
значение объекта берется из выражения; действуют те же огра-
ничения на тип и выполняемые преобразования, что и для прос-
тых присваиваний.

Для объединений заключенный в фигурные скобки инициали-
затор инициализирует компонент, появляющийся в списке
объявления объединения первым. Для структур и объединений с
автоматическим размещением в памяти инициализатор должен
быть одним из:

— списком инициализаторов, как описано в следующем раз-
деле
— отдельным выражением с типом, совместимым с объедине-
нием или структурой. В этом случае исходное значение объекта
берется из выражения.

Массивы, структуры и объединения

Вы инициализируете массивы и структуры (если хотите, то
во время объявления) при помощи заключенного в фигурные
скобки списка инициализаторов для компонентов илиэлементов
рассматриваемого объекта. Инициализаторы даются по возраста-
нию индекса массивов или номеров компонентов. Инициализация
объединенийвыполняется заключенным в фигурные скобки инициа-
лизатором для первого компонента объединения. Например, вы
можете объявить массив days, предназначенный для подсчета
того, сколько раз каждый день недели был в том или ином ме-
сяце (предполагая, что каждый день недели был в месяце хотя
бы один раз), следующим образом:

int days[7] = (* 1, 1, 1, 1, 1, 1, 1)

Этими правилами можновоспользоваться для инициализации
символьных массивов и широких символьных массивов:

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

— 45 —
инициализирует последовательно расположенные элементы масси-
ва. Например, вы могли объявить:

char name[] = (* «Unknown» *);

установив тем самым массив из восьми элементов, элемен-
ты которого равны ‘U'(для name[0]), ‘n’ (для name[1]), и
т.д. (включая нулевой терминатор.)

2. Вы можете инициализировать широкий символьный массив
(то есть совместимый с wchar_t), используя широкий строковый
литерал, опционально заключенный в фигурные скобки. Как и в
случае символьных массивов, коды широкого символьного лите-
рала последовательно инициализируют элементы массива.

Ниже приводится пример инициализации структуры:

struct mystruct (*
int i;
char str[21];
double d;
*) s = (* 20, «Borland», 3.14 *);

Сложные компоненты структуры,такиекак массивыили струк-
туры, могутбытьинициализированы соответствующими выражениями
во вложенных фигурных скобок. Можно убрать фигурные скобки,
но тогда приходится выполнять дополнительные правила, и та-
кая практика не рекомендуется.

Простые объявления

Простые объявления идентификаторов переменных имеют
следующий шаблон:

тип-данных перем1 , перем2 ,…;

где перем1, перем2, … это произвольная последователь-
ность отдельных идентификаторов с опциональными инициализа-
торами. Каждая из переменных объявляется с указанным ти-
пом-данных. Например,

int x = 1, y = 2;

создает две целочисленных переменных x и y (и
инициализирует их значениями 1 и 2, соответственно).

Это былиобъявления определения; при этом распределялась
память и выполнялась инициализация.

Инициализатор для динамического локального объекта мо-
жет представлять собой любое выражение, дающее при вычисле-
нии совместимое с типом участвующейв присваивании переменной
значение. Инициализаторы для статических объектов должны яв-
ляться константами или выражениями с константами.

В C++ инициализатор статического объекта может являться
любым выражением, включающим в себя константы и ранее опре-
деленные переменные и функции.

Страницы: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30

Turbo C++ Version 1.0 Programmer’s Guide

КОМПЬЮТЕРНАЯ ЛИТЕРАТУРА

LIB.com.ua [электронная библиотека]: : TURBO C++ Version 1.0 Programmer’s Guide

Спецификаторы класса памяти

Спецификатор класса памяти,или спецификатор типа, обя-
зательно должен присутствовать в объявлении. Спецификатор
класса памяти может быть одним из следующих ключевых слов:

auto register typedef
extern static

— 46 —

Использование спецификатора класса памяти auto

Спецификатор класса памяти auto используется только в
объявлениях переменных с локальным контекстом. Он подразуме-
вает локальную (автоматически определяемую) продолжитель-
ность, но поскольку это есть умолчание для всех объявлений
переменных локального контекста, то использование его редко.

Использование спецификатора класса памяти extern

Спецификатор класса памяти extern может быть использо-
ван в объявлениях функций и переменных с контекстом файла и
с локальным контекстом для обозначения внешнего типа компо-
новки. В случае переменных сконтекстом файла спецификатор
класса памяти extern является умолчанием.При использовании
спеременными extern указывает на то,что данная переменная
имеетстатическую продолжительность. (Помните, что функции
всегда имеютстатическую продолжительность).

Использование спецификатора класса памяти register

Спецификатор класса памяти registerдопустим только в
объявлениях локальных переменных и параметров функций. Он
эквивалентен класса auto, за исключением того, что компиля-
тору в данном случае делается запрос о размещении при воз-
можности данной переменной в регистре. Распределение для пе-
ременной регистра может значительно уменьшить размер
программы и увеличить скорость ее выполнения во многих слу-
чаях. Однако, поскольку TurboC++ итак предпринимает мерыдля
возможного размещения переменных в регистре, необходимость в
явном задании ключевого слова register возникает редко.

Turbo C++ позволяет вам выбрать опции размещения пере-
менных в регистрах в диалоговом поле Options \! Compiler \!
Optimization. При выборе опции Automatic TurboC++ сделает
попытку распределить регистры даже еслиспецификаторы класса
памяти register не задавались.

Использование спецификатора класса памяти static

Спецификатор класса памяти static может использоваться
в объявлениях функций и переменных с контекстом файла и ло-
кальным контекстом для обозначения внутреннего типакомпонов-
ки. Static также указывает, что переменная должна иметьста-
тическую продолжительность существования. При отсутствии
конструкторовили явныхинициализаторов статические переменные
инициализируются 0 или null.

В С++ компоненты класса,статические данные, имеет то же
значение длявсех вхождений класса. Члены класса, статические
функции, не зависят от других вхождений класса.

Использование спецификатора класса памяти typedef

Ключевое слово typedef означает, что вы не объявляете
объект, а определяете спецификатор нового типа данных.
typedef включается в качестве спецификатора класса памяти
вследствие синтаксических, а не функциональных аналогий.

static long int biggy;
typedef long int BIGGY;

Первое объявление создает 32-битовый объект типа long
int, со статической продолжительностью существования и име-
нем biggy. Второе объявление устанавливает идентификатор
BIGGY в качестве спецификаторановоготипа, не создавая при

— 47 —
этомкакого-либо объекта времени выполнения. BIGGY можно ис-
пользовать в последующих объявлениях,там, где допустимо за-
даватьспецификатор типа. Например,

extern BIGGY salary;

имеет тот же эффект, что и

extern long int salary;

Хотя данный простой пример может быть равным образом
реализован при помощи #define BIGGY long int, в более слож-
ных случаях typedef позволяет добиться большего, нежели с
помощью текстовых подстановок.

Важное замечание!

typedef не создает новых типов данных; это ключевое

слово просто создает полезные мнемонические синонимы, или
алиасы,для существующих типов. Это особенно полезно для уп-
рощения сложных объявлений:

typedef double (*PFD)();
PFD array-pfd[10];
/* array_pfd это массив из 10 указателей на функции,
возвращающие значения типа double */

Нельзя использовать идентификаторы typedef со специфи-
каторами других типов:

unsigned BIGGY pay; /* НЕДОПУСТИМО */
Модификаторы

Помимо ключевых слов спецификатора класса памяти, объ-
явление можетиспользовать конкретные модификаторы,
предназначенные для изменения некоторых аспектов распределе-
ния памяти идентификатора/ объекта. В следующей таблице све-
дены модификаторы, имеющиеся в Turbo C++.

Модификаторы Turbo C++ Таблица 1.16
————————————————————
Модификатор Используется с Использование
————————————————————
const Только переменными Предотвращает изменения объекта

volatile Только переменными Предотвращает распределение
регистров и некоторые виды оптимизации. Предупреждает компи-
лятор о том, что объект при вычислении может получить какие-
либо изменения извне.

В С++ const и volatile расширены и включают классы и
функции.

Расширения Turbo C++

cdecl Функции Устанавливает соглашения С пере-
дачи аргументов

cdecl Переменные Устанавливает учет регистра иден-
тификатора и ведущие знаки подчер-
кивания

pascal Функции Устанавливает соглашения пере-
дачи аргументов Паскаля

pascal Переменные отменяет учет регистра идентифи-

— 48 —
катора и ведущие знаки подчерки-
вания

interrupt Функции Функция компилируется с дополни-
тельным кодом управления реги-
стром, необходимыми при написании
обработчиков прерываний

near, Переменные Переопределяет умолчание типа
far, указатели указателя, задаваемое текущей
huge моделью памяти

_cs, Переменные Указатели сегмента;
_ds, указатели см. стр.199 оригинала
_es,
_seg,
_ss

near, Функции Переопределяет умолчание типа
far, функции, задаваемое текущей
huge моделью памяти

near, Переменные Определяет размещение объекта в
far, памяти

_export Функции Только OS/2. Turbo C++ это
игнорирует

_loadds Функции Устанавливает регистр DS на
текущий сегмент данных

_saveregs Функции Предохраняет все значения регис-
тров (кроме значений возврата)
во время выполнения функции
————————————————————
Модификатор const

Модификатор const предотвращает любые присваивания дан-
ному объекту, а также прочие побочные эффекты, такие как ин-
кремент или декремент объекта. Указатель const неможет быть
модифицирован, хотя сам объект, на который он указывает, мо-
жет. Рассмотрим следующие примеры:

const float pi= 3.1415926;
const maxint = 32767;
char *const str= «Hello, world!»; // указатель константа
char const *str2= «Hello, world!»; // указатель на
константу

Использование одного только модификатораconst эквива-
лентно const int.

Страницы: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30