приведет к тому, что в W будет записано значение 257. Если надо заполнить не всю структуру, а часть ее, то следует указать идентификатор того элемента структуры, начиная с которого надо проводить заполнение. Так, можно заполнить средние элементы массива A:

VAR

А : Array [ 1..500 ] of LongInt;

BEGIN

FillChar( A[ 100 ], 200 * SizeOf( LongInt ), 0 );

...

END.

В этом примере 200 значений типа LongInt массива A, начиная с 100-го, будут заполнены нулем.

С особой осторожностью надо заполнять строки символами, так как нужно заботиться о нулевом байте строки. Подробно об этом говорилось в гл. 8 «Обработка символов и строк».

Кроме того, надо всегда следить за согласованностью реального размера переменной (первого параметра) и длины заполняемого блока (значением NBytes). Если длина блока превышает размер переменной, то будут заполнены байты ОЗУ, следующие за переменной, но к ней уже не относящиеся! Иными словами, если A — статическая переменная или разыменованная ссылка, то следует придерживаться правила

NBytes <= SizeOf( A ).

Сам Турбо Паскаль проверок на корректность параметров не производит.

То, что процедура FillChar заполняет все по байтам, не всегда удобно. В справочном руководстве по Турбо Паскалю приводится пример функции в машинных кодах, заполняющей области памяти так же, как FillChar, но значениями типа Word — по 2 байта сразу (рис. 14.4).

- 301 -

| PROCEDURE FillWord( VAR V; NWords, Fill : Word );

| BEGIN

| inline(

| $C4/$BE/ V / { LES DI, bp+V}

| $8B/$8E/ NWords/ { MOV CX, bp+NWords }

| $8B/$86/ Fill/ {MOV AX, bp+Fill}

| $FC/ { CLD }

| $F3/$AB ) { REP STOSW }

| END;

| VAR

| P : Pointer;

| BEGIN

| P := Ptr( $B800, 0 ); {Начало памяти экрана для цветных мониторов; для монохромных надо задавать P := Ptr( $8000, 0 ) }

| FillWord( Р^, 80*25, 176 + 14 * 256 );

| ReadLn

| END.

Рис. 14.4

На рис. 14.4 дан пример заполнения области экрана (размером 80x25 видимых символов) символом #176 цветом номер 14. Код и цвет скомбинированы в одно значение типа Word. При таком заполнении помните, что первым в машинном представлении слова (Word) идет младший байт, а следом за ним — старший (значение множителя при 256). Обратите внимание на разыменование указателя P, что означает передачу в FillWord адреса начала видеоизображения, а не самого значения P.

<p>14.5. Процедура перемещения данных Move</p>

Процедура Move в некотором роде — уникальная. Она практически не имеет аналогов в стандартах языков высокого уровня. По своей сути она скорее является командой машинного уровня. Процедура содержит три параметра:

Move( VAR Source, Dest; NBytes : Word )

и служит для перемещения в ОЗУ блоков данных размером NBytes. Начало блока задается переменной Source любого типа (первый байт блока соответствует первому байту значения Source). Переменная Dest, точнее задаваемый ею первый байт, указывает на место в

- 302 -

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

Очень эффективно работает процедура Move в различных трюках программистов, таких как копирование области видеопамяти (см. пример к процедуре Keep модуля DOS). Но не менее эффективно ее можно использовать и в более традиционных задачах. Например, копирование массива B в массив A:

А := В;

может быть выполнено процедурой

Move( В, A, SizeOf( В ) );

т.е. блок байтов — значений массива B соответствующего размера — будет скопирован в область памяти, занимаемую массивом A. В этом случае применение Move не дает особого эффекта. Но если, например, нам надо скопировать одну структуру в другую, причем сами структуры — разнотипные, то Move позволяет проделать это максимально просто и с наибольшим быстродействием (рис. 14.5). В этом случае не надо уже беспокоиться об индексах, а надо только указать размер копируемого блока.

| VAR R : RECORD { запись R : } X, Y :Integer; { поля-числа } Arr : Array [ 20..120 ] of Real; { поле-массив } S :String { поле-строка } END; A : Array [ 1..500 J of Real; { массив А } i : Word; BEGIN {Традиционное решение: for i:=20 to 120 do A[ i-19 ] := R.Arr[ i ]; } { Оптимальное решение : } Move( R.Arr, A, SizeOf( R.Arr ) ); END.

Рис. 14.5

Еще одна область приложения, где Move эффективнее прочих способов — это перемещение значений (сдвиг) внутри одного массива. Пусть, к примеру, объявлен массив

VAR

A : Array[ 1..10000 ] of Real;

- 303 -

Перейти на страницу:

Поиск

Похожие книги