рефераты

рефераты

 
 
рефераты рефераты

Меню

Реферат: Turbo C++ Programer`s guide рефераты

- Когда сегментные указатели используются в косвенном выражении они также преобразуются в far-указатели.

- Также как и расширениек двоичному + оператору, если сегментный указатель прибавляется к near-указателю, результатом будет far-указатель, который формируется путем взятия сегмента из сегментного указателя исмещения из near-указателя. Такая операция разрешается, только если оба указателя указывают на одинаковый тип, илиесли один из указателей указывает на тип void.

- Указатели сегментов можно сравнивать. Сравнение их выполняется таким образом, как если бы их значения имели целочисленный тип unsigned.

Функции и указатели в данной программе по умолчанию бывают ближними или дальними, в зависимости от выбранной модели памяти.  Если функция или указатель являются ближними, то они автоматически связываются с регистром CS или DS.

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

Типы указателей                        Таблица 4.2

Модель памяти Указатели функции Указатели данных

Tiny near, _csnear, _ds

Small near, _csnear, _ds

Medium farnear, _ds

Compact near, _csfar

Large farfar

Huge farfar

Указатели данных могут быть также объявлены с модификатором _seg. Это 16-битовые указатели сегмента.

Объявление ближних или дальних функций

В некоторых случаях вам может захотеться(или понадобиться) переопределить умолчание типа функции для модели памяти, показанное в таблице 4.1 (стр.198 оригинала).

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

double  power(double x,int exp)

(*

if (exp <= 0)

return(1);

else

return(x * power(x, exp-1));

*)

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

double near power(double x,int exp)

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

Это означает, что при использовании большой модели памяти (medium, large или huge) power можно вызывать только из того модуля, в котором она определена.Прочиемодулиимеют свои собственные кодовые сегменты и не могут вызывать функции near из других модулей. Более того, ближняя функциядо первого кней обращения должна быть либоопределена, либо объявлена, иначе компилятор не знает о необходимости генерировать ближний вызов.

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

Вернемся к примеру функции power. Хорошо также объявить power как static, поскольку предусматривается вызывать ее только из текущего модуля. Если функция будет объявлена как static, тоимя ее не будет доступно ни одной функции вне данного модуля.

Объявление указателей 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 */

*)

Теперь при компиляции вашей программы Turbo C++ знает, что myputs ожидает указатель на char; и поскольку компиляция выполняется с моделью large, то известно, что указатель должен быть far. Вследствие этого Turbo C++ поместит в стек регистр сегмента данных (DS) и 16-битовоезначение mystr, образуя тем самым дальний указатель.

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

Как быть в обратном случае: когда аргументы myputs объявлены как far, а компиляция выполняется с моделью памяти small? И в этом случае без прототипа функции у вас возникнут проблемы, поскольку main будет помещать в стек и смещение, и адрес сегмента, тогда как myputs будет ожидать приема только одного смещения. При наличии определений функций в прототипах main будет помещать в стек только смещение.

Создание указателя данного адреса сегмент:смещение

Как создать дальний указательна конкретный адрес памяти (конкретный адрессегмент:смещение)? Для этого можно воспользоваться встроеннойбиблиотечной подпрограммой MK_FP, которая в качестве аргументапринимает сегмент и смещение, и возвращает дальний указатель. Например,

MK_FP(segment_value, offset_value)

Имея дальний указательfp, вы можете получить компонент сегмента полного адреса с помощью FP_SEG(fp) и компонент смещения с помощью FP_OFF(fp). Более полную информацию об этих трех библиотечных функциях Turbo C++ см. в Справочнике по библиотеке.

Использование библиотечных файлов

Turbo C++ предлягает для каждой из шести моделей памяти собственную версию библиотеки стандартных подпрограмм. Turbo C++ при этом проявляет достаточно "интеллекта", чтобы при компоновке брать нужные библиотеки и в нужной последовательности, в зависимости от выбранной вами модели памяти. Однако,при непосредственном использовании компоновщика Turbo C++ TLINK (как автономного компоновщика) вы должны явно указывать используемые библиотеки. Более подробно это описано в разделе TLINK Главы 5Б "Утилиты", Руководства пользователя.

Компоновка смешанных  модулей

Что произойдет,если вы компилируете один модуль с использованием модели памяти small, второй - модели large, и затем хотите скомпоновать их? Что при этом произойдет?

Файлы скомпонуются удовлетворительно, но при этом вы встретитесь с проблемами, которые будут аналогичны с описанными выше в разделе "Объявление функций как near или far". Если функция модуля с моделью small вызывает функцию в модуле с моделью large, она будет использовать при этом ближний вызов, что даст абсолютно неверные результаты.Кроме того, у вас возникнут проблемы с указателями, описанные в разделе "Объявление указателей как near, far или huge", поскольку функция в модуле small ожидает, что принимаемые и передаваемые ейуказатели будут near, тогдакак функция в модуле large ожидает рабрту с указателями far.

И снова решение заключается в использовании прототипов функций. Предположим, что вы поместили myputs в отдельный модуль и скомпилировали его с моделью памяти large. Затем вы создаете файл заголовка myputs.h (либо с любым другим именем и расширением .h), который содержит следующий прототип функции:

void far myputs(char far *s);

Теперь, если поместить main в отдельный модуль (MYMAIN.

C) и выполнить следующие установки:

#include <stdio.h>

#include "myputs.h"

main()

(*

char near *mystr;

mystr = "Hello, wirld\n";

myputs(mystr);

*)

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

Что произойдет, если помимо этого вам требуется компоновка с библиотечными подпрограммами? Лучший подход здесь заключается в том, чтобы выбрать одну из библиотек с моделью large и объявить все как far. Для этого сделайте копии всех файлов заголовка, которые вы обычно включаете (таких, как stdio.h) и переименуйте эти копии (например, fstdio.h).

Затем отредактируйте копии прототипов функций таким образом, чтобы там было явно указано far, например:

int far cdecl printf(char far* format, ...);

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

#include <fstdio.h>

main()

(*

char near *mystr;

mystr = "Hello, world\n";

printf(mystr);

*)

Скомпилируйте вашу программу при помощиTCC, затем скомпонуйте ее при помощью TLINK, указав библиотеки с моделью памяти large, напрмер CL.LIB. Смешиваниемодулей с разными моделями - вещь экстравагантная, но допустимая; будьте, однако, готовы к тому, чтолюбые неточности здесь приводят к ошибкам, которые очень трудно найти и исправиь при отладке.

Опции типа чисел с плавающей точкой

С работает с двумя числовыми типами:интегральным (int, short, long и т.д.) и с плавающей точкой (float double и long double). Процессор вашего компьютер легко справляется с обработкой чисел интегральных типов, однако числа с плавающей точкой отнимают больше времени и усилий.

Однако, семейство процессоров iAPx86 имеет сопутствующееему семейство математических сопроцессоров, 8087, 80287 и

80387. Мы будем обозначать все семейство математических сопроцессоров 80x87 термином "сопроцессор".

В случае процессора80487вы имеете математический сопроцессор уже встроенным в основной.

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

Эмулирование платы 80х87

По умолчанию в Turbo C++ устанавливается опция генерации кода "эмуляция" (опция компилятора командной строки -f). Эта опция предназначена для программ, которые могут вообще не иметь операций с плавающей точкой, а также для программ, которые должны идти и на машинах, на которых сопроцессор 808 х87 не установлен.

В случае опции эмуляции компилятор генерирует код, как если бы сопроцессор имелся, но при компоновке подключает библиотеку эмуляции операций сплавающей точкой (EMU.LIB). При выполнении такой программы сопроцессор 80х87, если он установлен, будет использоваться; если же во время выполнения процессора не окажется, то программа будет использовать специальноепрограммное обеспечение, эмулирующее 80х87.

Получение кода только для машин с 80х87

Если вы планируете использовать вашу программу исключительно на машинах с установленным математическим сопроцессором 80х87, то можно сэкономить около 10К памяти программы, опустив из нее логику автоматического определения присутствия 80х87 и эмулятора. Для этого следует просто выбратьопцию генерации кодаопераций с плавающей точкой при наличии 80 х87 (или опциюкомпилятора командной строки -f87). Turbo C++ в этом случае скомпонует вашу программу с библиотекой FP87.LIB вместо EMU.LIB.

Получение кода без операций с плавающей точкой

При отсутствии в программе операций с плавающей точкой вы можете сэкономить немного времени компиляции, выбрав опцию генерации операций с плавающей точкой None ("отсутствуют") (или опцию компилятора командной строки -f-). Тогда Turbo C++ не будет выполнять компоновку ни с EMU.LIB, ни с FP87.LIB, ни с MATHx.LIB.

Опция быстрых вычислений с плавающей точкой

Turbo C++ имеет опцию быстрых вычислений с плавающей точкой (опция компилятора командной строки -ff). Выключить эту опцию можнопри помощи опции командной строки -ff-. Ее назначение состоит в выполнении некоторой оптимизации, противоречащей правильной семантике С. Например,

double x;

x = (float)(3.5*x);

Для вычисления по обычным правилам x умножается на 3.5, давая точность результата double,которая затем усекается до точности float, после чего x записывается какdouble. При использовании опции быстрых вычислений с плавающей точкой произведение типа long double преобразуетсянепосредственно в double. Поскольку лишь очень немногие программы чувствительны к потере точностипри преобразовании от более точного к менее точному типу с плавающей точкой, то данная опция является умолчанием.

Переменная операционной среды 87

При построении программы с эмуляцией 80x87, которая устанавливается по умолчанию, ваша программа станет автоматически проверять наличие 80х87 и использовать его, если он установлен в машине.

Существует ряд ситуаций, в которых вам может понадобиться отменить режим автоматического определения наличия сопроцессора по умолчанию. Например, вашасобственная исполняющая система можетиметь 80х87, но вам требуется проверить, будет ли программа работать так, как вы предполагали, в системебез соопроцессора. Либоваша программа предназначена дляработыв системе, совместимой с PC, но данная конкретная система возвращает логике автоматического определения наличия сопроцессора неверную информацию (либо при оссутствии 80х87 говорит, что он на месте, либо наоборот).

Turbo C++ имеет опцию для переопределения логики определения наличия сопроцессорапри загрузке программыж эта опция - соответствующая переменная операционной среды системы

87.

Переменная операционной среды 87 устанавливается по приглашению DOS при помощи команды SET:

C>SET 87=N

или

C>SET 87=X

Ни с какой стороны знака равенства не должно быть пробелов. Установка переменной операционной среды 87 в N (это значит "Нет") говорит загрузочному коду исполняющей системы о том,что вы не хотите использовать 80х87 даже в том случае, если он установлен в системе.

Установка переменной операционной среды в Y ("Да") означает, что сопроцессор на месте и вы желаете, чтобы программа его использовала.Программист должен знать следующее: !!! Если установить 87=Y, а физически 80х87 в системе не установлен, то система повиснет.

Если переменная операционной среды 86 была определена (в любоезначение), и вы желаете сделать ее неопределенной, введите на приглашение DOS:

C>SET=

Непосредственно после знака равенстванажмите Enter, и переменная 87 станет неопределенной.

Регистры и 80х87

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

1. В режиме эмуляции 80Х87 циклический переход в регистрах, а также ряд других особенностей 80х87 не поддерживается.

2. Если вы смешиваете операции с плавающей точкой и встроенные коды на языке ассемблера, то при использовании регистров вы должны принимать некоторые меры предосторожности. Это связано с тем, что набор регистров 80х87 перед вызовом функции в Turbo C++ очищается. Вам может понадобиться извлечь из стека и сохранить регистры 80х87 до вызова функции, использующей сопроцессор, если вы не уверены, что свободных регистров достаточно.

Отмена обработки особых ситуаций

для операций с плавающей точкой   -------------------------

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

#include <floar.h>

main() (*

_control87(MCW_EM,MCW_EM);

...

*)

Вы можете определить особую ситуацию для операции с плавающей точкой, вызвав функции _status87 или _clear87. См. описания этих функций в Главе 1 Справочника по библиотеке.

Определенные математические ошибки могуттакже произойти в библиотечных функциях; например, при попытке извлечения квадратного корня из отрицательного числа. Поумолчанию в таких случаях выполняется вывод на экран сообщений об ошибке и возврат значения NAN (код IEEE "not-a-number -- "не-число"). Использование NAN скорее всего приведет далее к возникновению особой ситуации с плавающей точкой, которая в свою очередь вызовет , если она не замаскирована, аварийное прерывание программы. Если вы не желаете, чтобысообщение выводилось на экран, вставьте в программу соответствующую версию matherr.

#include <math.h>

int cdecl matherr(struct exception *e)

(*

return 1;                    /* ошибка обработана */

*)

Любое другое использование matherr для внутренней обработки математических ошибок недопустимо,так как она считается устаревшей иможет не поддерживаться последующими версиями Turbo C++.

Математические операции с комплексными числами

Комплексными называются числа вида x +yi, где x и yэто действительные числа, а i это корень квадратный из -1. В Turbo C++ всегда существовал тип

struct complex

(*

double x, y;

*);

определенный в math.h. Этот тип удобен для представления комплексных чисел, поскольку их можно рассматривать в качестве пары действительных чисел. Однако, ограничения С делают арифметические операции с комплексными числами несколько громоздкими. В С++ операции с комплексными числами выполняются несколько проще.

Для скомплексными числами в С++ достаточно включить complex.h. В complex.h для обработкикомплексных числе перегружены:

Страницы: 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