Объявление указателей 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 будет
помещать в стек только смещение.