Четвертый Borland C++ и его окружение

Объявление указателей near, far или huge


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

часть программы. Зачем то же самое может понадобиться для указателей? По тем же причинам, что и для функций: либо для улучшения

характеристик быстродействия (объявив __near там, где по умолчанию было бы __far), либо для ссылки за пределы сегмента по умолчанию (объявив __far или __huge там, где по умолчанию бывает

__near).

Разумеется, при объявлении функций или указателей с другим

типом, нежели используемый по умолчанию, потенциально появляется

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

void myputs(s)

char *s;

{

int i;

for (i = 0; s[i] != 0; i++) putc(s[i]);

}



main()

{

char near *mystr;

mystr = "Hello, world\n";

myputs(mystr);

}

Эта программа работает удовлетворительно, хотя объявление

mystr как __near избыточно, поскольку все указатели, как кода,

так и данных, будут ближними (near) по умолчанию.

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

с моделью памяти compact (либо large или huge)? Указатель mystr в

функции main останется ближним (16-битовым). Однако, указатель s

в функции myputs теперь будет дальним (far), поскольку по умолчанию теперь используется far. Это означает, что попытка создания

дальнего указателя приведет к извлечению из стека двух слов, и

полученный таким образом адрес, безусловно, не будет являться адресом функции mystr.

Как избежать этой проблемы? Решение состоит в том, чтобы определить myputs в современном стиле Си:

void myputs(char *s)

{

/* тело myputs */

}

Теперь при компиляции вашей программы Borland C++ знает, что

myputs ожидает указатель на char. Поскольку компиляция выполняется с моделью large, то известно, что указатель должен быть __far.

Вследствие этого Borland C++ поместит в стек регистр сегмента

данных (DS) и 16-битовое значение mystr, образуя тем самым дальний указатель.

Если вы собираетесь явно объявлять указатели как far или near, не забывайте использовать прототипы тех функций, которые могут работать с этими указателями.

Как быть в обратном случае: когда аргументы myputs объявлены

как __far, а компиляция выполняется с моделью памяти small? И в

этом случае без прототипа функции у вас возникнут проблемы, поскольку функция main будет помещать в стек и смещение, и адрес

сегмента, тогда как myputs будет ожидать приема только одного

смещения. При наличии определений функций в прототипах main будет

помещать в стек только смещение.



Содержание раздела