Скачиваний:
58
Добавлен:
04.03.2014
Размер:
41.98 Кб
Скачать

МАНИПУЛИРОВАНИЕ БЛОКАМИ ПАМЯТИ

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

Чтобы унифицировать разнообразие возможных практических реализаций этих операций манипулирования блоками памяти, система программирования C предоставляет набор стандартных функций. Имена этих функций начинаются с префикса mem, а объектный код сосредоточен в стандартной библиотеке объектных модулей системы программирования C. Прототипы их вызова могут быть декларированы в заголовочных файлах mem.h, memory.h или string.h системы программирования C. Заголовочные файлы memory.h и mem.h были введены в реализациях системы программирования C для OS Unix System V и Borland C, соответственно. Современные стандарты требуют использовать заголовочный файл string.h, который объединяет декларации прототипов функций манипулирования блоками памяти и обработки символьных строк, отражая концептуальное сходство выполняемых ими операций. Однако, любой из перечисленных файлов заголовков декларирует прототипы пяти базовых функций манипулирования блоками памяти, специфицируя типы их аргументов и кодов возврата. Это функции memset, memcpy, memmove, memcmp и memchr, которые есть в любых реализациях системы программирования C.

Для однородной инициализации блоков памяти применяется функция memset. Спецификация формата ее вызова имеет вид:

void* memset(void* mem, int code, unsigned len);

Корректный вызов этой функции обеспечивает заполнение начальных len байтов области памяти, адресуемой через указатель mem, значением кода символа, который задает младший байт параметра code. Функция memset возвращает адрес инициализированного блока памяти, то есть значение своего первого аргумента mem.

Применение функции memset поясняет следующий исходный код прикладной процедуры zero, которая обнуляет заданное число начальных байтов адресованной области память:

/* Обнуление области памяти */

void zero(void* mem, unsigned len) {

memset(mem, '\0', len);

} /* zero */

Для копирования блоков памяти используются функции memcpy и memmove. Спецификации форматов их вызовов имеют вид:

void* memcpy (void* dest, const void* src, unsigned len);

void* memmove(void* dest, const void* src, unsigned len);

Обе функции идентичны по набору аргументов и коду возврата. Они должны обеспечивать копирование начальных len байтов исходной области памяти, адресуемой указателем src, в блок памяти, который назначен указателем dest, передавая его адрес через код возврата. Функция memcpy реализует прямую передачу данных между адресованными областями памяти. Поэтому ее целесообразно применять при обработке неперекрывающихся областей, чтобы гарантировать однозначность результата копирования. Функция memmove использует для передачи данных внутренний промежуточный массив, который не пересекается с адресуемыми областями памяти. Это позволяет получить однозначный результат копирования независимо от взаимного расположения заданных областей памяти в адресном пространстве программы, но ценой расхода дополнительных ресурсов. Следует учитывать, что при обработке перекрывающихся областей памяти, операция копирования имеет характер перемещения данных внутри блока памяти, причем, содержимое исходного блока может быть модифицировано.

Операции копирования блоков памяти функциями memcpy и memmove поясняет следующий фрагмент исходного кода, который обеспечивает инициализацию и модификацию символьного массива римских цифр:

char rom[5]; /* массив для римских цифр */

memcpy(rom, "XVI", 3); /* инициализация массива */

memmove(&rom[1], rom, 3); /* модификация массива */

В приведенном фрагменте исходного кода функция memcpy копирует в пустой массив rom символы XVI, которые обозначают число 16 в римской системе счисления. После модификации в функции memmove, содержимое массива rom составляют символы XXVI, которые обозначают число 26 в римской системе счисления.

Сравнение блоков памяти реализует функция memcmp. Формат ее вызова имеет вид:

int memcmp(const void* mem1, const void* mem2, unsigned len);

Функция memcmp последовательно сравнивает значения первых len байтов, занимающих одинаковые позиции в областях памяти, которые адресуют указатели mem1 и mem2. Сопоставляемые байты интерпретируются как данные типа unsigned char. Процесс сопоставлений значений байтов прерывается, когда будет обнаружена первая пара несовпадающих байтов или исчерпан диапазон сравнения, который установлен значением параметра len. Результат сравнения функция memcmp передает через код возврата. Нулевой возврат имеет место, когда адресованные блоки памяти идентичны в заданном диапазоне сравнения. При наличии несовпадений код возврата функции memcmp не равен нулю. Его знак совпадает со знаком разности значений первой пары несовпадающих байтов сравниваемых областей памяти. Например, сравнение блоков памяти двух массивов, содержащих по паре 16-ти разрядных целых чисел без знака, специфицирует следующий фрагмент исходного кода:

static unsigned short june[] = { 0X756A, 0X656E };

static unsigned short july[] = { 0X756A, 0X796C };

unsigned len = 2 * sizeof(unsigned short); /* 2 * 2 */

int rez = memcmp(july, june, len);

В условиях этого примера функции memcmp возвращает отрицательное значение. Для реализации сравнения функция она интерпретирует массивы july и june как блоки памяти, которые содержат следующие последовательности байтов: 6A756C79 и 6A756E65, соответственно, где каждый байт кодирует пара цифр системы счисления по основанию 16. Таким образом, результат сравнения массивов july и june определяет знак разности первой пары несовпадающих байтов со значениями 6C и 6E, которая, очевидно, меньше нуля.

Практическое применение операции сравнения блоков памяти демонстрирует исходный код прикладной функции memident. Она реализует циклический вызов функции memcmp, чтобы определить количество начальных байтов, значения которых равны в адресованных блоках памяти заданного размера.

/* Измерение степени совпадения блоков памяти */

int memident(const void* mem1, const void* mem2, unsigned len) {

int count; /* счетчик совпадения блоков памяти */

for(count = len; count > 0; count--)

if(memcmp(mem1, mem2, count) == 0)

break;

return(count);

} /* memident */

При вызове функции memident для измерения длины совпадающих начальных фрагментов, например, целочисленных массивов july и june, которые были специфицированы выше для иллюстрации действия функции memcmp, будет получен результат: два байта.

Для выполнения операции поиска необходимой информации в блоках памяти предусмотрена функция memchr. Спецификация формата ее вызова имеет вид:

void* memchr(const void* mem, int src, unsigned len);

При вызове функция memchr последовательно рассматривает не более, чем len байтов области памяти, адресуемой через указатель mem, чтобы найти первый байт, который имеет значение, заданное параметром src. Функция memchr интерпретирует все байты, значения которых сравниваются при поиске, как данные типа unsigned char. Функция memchr возвращает адрес найденного байта при успехе поиска или нулевой указатель NULL, если заданный байт не обнаружен.

Рассмотренная стандартная функциональная реализация операции поиска может быть использована для конструирования разнообразных прикладных процедур контекстной обработки содержимого блоков памяти. В частности, следующий исходный код прикладной функции memrpl демонстрирует, каким образом можно применить стандартную функцию memchr для организации контекстной замены определенных байтов блоков памяти.

/* Контекстная замена байтов блока памяти */

unsigned memrpl(void* mem, int src, unsigned len, int dest) {

unsigned count = 0; /* счетчик замен */

unsigned char* ptr; /* адрес замены */

/* Цикл поиска и замены */

while((ptr = memchr(mem, src, len)) != NULL) {

*ptr = dest; /* замена значения байта */

count++; /* увеличение счетчика замен */

} /* while */

return(count); /* Возврат общего числа замен */

} /* memrpl */

Функция memrpl обеспечивает замену всех байтов со значением src в блоке памяти длиной len байтов, который адресуется через указатель mem, новым значением, заданным параметром dest. Адреса заменяемых байтов блока памяти предоставляет циклический вызов функции memchr. Суммарное число сделанных замен функция memrpl передает через код возврата.

В заключение следует отметить, что во многих популярных версиях системы программирования C стандартный набор функций манипулирования блоками памяти расширяют дополнительные процедуры, уникальные только для данной конкретной реализации. В частности, в системе программирования Borlan C для манипулирования блоками памяти дополнительно к стандартным введены функции setmem, movedata и memicmp, а также функция memccpy, которая включена в стандартную библиотеку объектных модулей некоторых версий OS Unix. Однако, при разработке мобильного программного обеспечения целесообразно воздержаться от использования специфических особенностей отдельных реализаций и применять только стандартные функции обработки блоков памяти.

Соседние файлы в папке Инфа - бесценно