C_Kurs_Lekt / C_III_семестр / 17-5_РАБОТА С МНОГОФАЙЛОВЫМИ ПРОЕКТАМИ
.pdfРАБОТА С МНОГОФАЙЛОВЫМИ ПРОЕКТАМИ Поскольку большинство программ состоит из нескольких файлов, желательно иметь
возможность автоматически определять те файлы, которые необходимо перекомпилировать и скомпоновать. Эти и многие другие обязанности выполняет встроенный администратор проектов системы Borland C++
Администратор проектов позволяет задавать те файлы, которые относятся к описываемому проекту. Когда вы осуществляете перекомпиляцию проекта, администратор проектов автоматически обновляет информацию, которая хранится в файле проекта. В файл проекта входит следующая информация:
-имена всех файлов, входящих в проект;
-где их следует искать на диске;
-файлы заголовка для каждого из исходных модулей
-какие компиляторы и параметры командной строки должны использоваться при создании каждой из частей программы;
-куда следует поместить результирующую программу;
-размер кода, размер данных и число строк, полученных в результате последней компиляции.
Сохраненный на диске проект будет состоять из двух файлов: файла проекта (с расширением имени .PRJ) и файла состояния рабочей области (с расширением имени .DSK).
Файл проекта содержит информацию, которая необходима для построения исполняемого файла (с расширением имени .EXE), связанного с проектом. Необходимая для построения исполняемого файла информация состоит из параметров компилятора, имен маршрутов INCLUDE/LIB/OUTPUT, файлов библиотек и результирующих файлов, параметров компоновщика, параметров выполнения избирательной компиляции и программ из пункта Transfer.
Файл состояния рабочей области экрана состоит из информации состояния по всем окнам на момент последнего использования данного проекта.
В период компиляции администратор проектов собирает информацию по зависимостям и сохраняет ее таким образом, что необходимо обрабатывать только те файлы, которые компилировались вне интегрированной среды. Администратор проектов может автоматически проверять зависимости между исходными файлами в списке проекта (в том числе по файлам, которые включаются в эти файлы проекта) и соответствующими им объектными файлами. Это оказывается полезным в том случае, когда конкретный исходный файл на языке С++ зависит от других файлов. Для исходного файла на языке С++ типично включение нескольких файлов заголовков (с расширением имени .h), в которых описывается интерфейс с внешними программами. Если интерфейс с этими программами меняется, то вы захотите перекомпилировать тот файл, в котором используются эти подпрограммы.
Если параметр Auto-Deрendencies (Options¦Make) был включен, то Make получает временную информацию для всех файлов .CPP и ими включаемых. Далее Make сравнивает показания даты и времени для этих файлов с датой и временем последней компиляции. Если какие-либо дата и время различны, то происходит перекомпиляция.
Если параметр Auto-Dependencies отключен, то файлы .CPP сравниваются с файлами
.OBJ. Если существует более ранний файл с расширением .CPP, то происходит перекомпиляция.
Пункты: Project: Oрen Project; Close Project; Add item; Delete Item; Local Options; Include files. Window: Project, Project notes.
Local Oрtions позволяет включить параметры переопределения командной строки для конкретного модуля проекта. Он позволяет также задать объектному файлу конкретное имя маршрута (идентификатор диска + имя катало га), а также само имя этого файла.
Команда Comрile (Компилировать) - компилирует файл, находящийся в активном окне редактора.
Команда Make вызывает администратор проектов для создания файла EXE или библиотеки.
Команда Link берет текущие файлы, задаваемые либо в файле проекта, либо по умолчанию, и компонует их.
Команда Build (Полная перекомпиляция и перекомпоновка всех файлов)
АВТОНОМНЫЙ КОМПИЛЯТОР В дополнение к использованию интегрированной среды разработки программ вы можете
компилировать и выполнять свои программы с помощью автономного компилятора (BCC.EXE), запускающегося из командной строки DOS.
Запуск BCC, типичный формат командной строки (Можно также использовать файл конфигурации TURBOC.CFG или альтернативный):
BCC [параметр[параметр...]]имя-файла[имя-файла...]
Каждому параметру командной строки предшествует знак дефиса (-) или косая черта (/). Каждый параметр должен отделяться от команды BCC, других параметров и последующих имен файлов по меньшей мере одним символом пробела.
Правила приоритета параметров просты; параметры командной строки оцениваются слева направо, и, кроме того, действуют следующие правила:
Для любых параметров, кроме -l и -L, повторение параметра справа отменяет действие того же параметра слева. (То есть, выключение параметра справа отменяет включение параметра слева). Параметры -l и -L слева имеют приоритет перед теми же параметрами справа.
Параметр |
Действие |
@<имя_файла> |
Задает автономному компилятору имя управляющего файла с |
|
параметрами компилятора |
+<имя_файла> |
Предписывает автономному компилятору использовать |
|
альтернативный файл конфигурации <имя-файла>. |
-1- |
Генерировать команды 8088 (установлено по умолчанию) |
-3 |
Генерировать инструкции процессора 80386 |
-c |
Компилировать в объектный файл, но не компоновать |
-A- èëè -AT |
Использовать ключевые слова системы Borland C++ (по умолчанию) |
-e<имя_файла> |
В результате компоновки получить <имя_файла> .EXE. |
-f |
Эмуляция математики с плавающей точкой (используется по |
|
умолчанию) |
-ff |
Быстрые операции с плавающей точкой (используется по |
|
умолчанию) |
-f287 |
Использовать набор команд сопроцессора 80287 |
-G èëè -O2 |
Оптимизировать по скорости |
-G- èëè -O1 |
Оптимизировать по размеру (используется по умолчанию) |
-Od |
Отключить все виды оптимизации. |
-I<маршрут> |
Каталоги для включаемых файлов. |
-L<маршрут> |
Каталоги для библиотек |
-l<x> |
Передать параметр x компоновщику (может использоваться более |
|
одного x, -l задается после всех ключей) -lm => /lib/libm.a (libm.a – |
|
библиотека математических функций) |
-n<маршрут> |
Каталог результирующих файлов |
-o<имя_файла> |
Компилировать исходный файл в объектный файл <имя_файла> |
|
.obj. |
-v,-v- |
Включить отладочную информацию |
-mc, -mh, -ml, - |
Компилировать с использованием компактной, огромной, большой, |
mm, -ms, -mt |
средней, малой(по умолчанию), крохотной модели памяти |
-w |
Разрешить отображение предупреждающих сообщений |
-j<n> |
Ошибки: остановить обработку после <n> сообщений. |
-g<n> |
Предупреждающие сообщения: остановить обработку после <n> |
|
сообщений. |
-N |
Проводить проверку переполнения стека. |
-P |
Выполнить компиляцию для языка C++ вне зависимости от |
|
расширения имени файла. |
-P- |
Выполнить компиляцию для языка C++ или Cи в зависимости от |
|
расширения имени файла (используется по умолчанию) |
Синтаксис и имена файлов
Система Borland C++ компилирует файлы в соответствии со следующими правилами: <имя_файла>.asm Вызывает TASM для ассемблирования в .OBJ
<имя_файла>.obj Использует при компоновке объектный файл <имя_файла>.lib Использует при компоновке библиотеку <имя_файла> Компилирует <имя_файла>.CPP <имя_файла>.cрр Компилирует <имя_файла>.CPP <имя_файла>.c Компилирует <имя_файла>.C <имя_файла>.xyz Компилирует <имя_файла>.XYZ
Примеры:
bcc –emyprog -Id:\bc\include -ld:\bc\lib func_4.c fun.c bcc –ñ –ofile1 -Id:\bc\include -ld:\bc\lib fun.c
FUNC_4.C
/* Пример projecta*/ #include <stdio.h> #include <stdlib.h> #include <conio.h> #include "myfun.h" void main(){
int n,m,i; double **dmas; clrscr();
printf(" N, M =? "); scanf("%d,%d",&n,&m);
dmas=(double **)malloc(n*sizeof(double *));
for (i=0; i<n;i++) |
dmas[i]=(double *)calloc(m,sizeof(double)); |
start_data(n, m, dmas); |
|
pech(n, m, dmas); |
|
for (i=0; i<n;i++) free(dmas[i]); free(dmas);
getch();
}
FUN.C
#include <stdio.h> #include <stdlib.h>
void start_data(int row, int column, double **mass){ int i,j;
for (i=0;i<row;i++)
for (j=0;j<column;j++) mass[i][j]=rand();
}
void pech(int row, int column, double **mass){
int |
i,j; |
|
for |
(i=0;i<row;i++){ |
for (j=0;j<column;j++) |
printf(" %7.1lf ", mass[i][j]); printf("\n"); }
}
MYFUN.H
void start_data(int, int, double **); void pech(int, int, double **);
Директивы препроцессора.
Для управления препроцессором, т.е. для задания нужных действий, используются команды (директивы) препроцессора, каждая из которых помещается на отдельной строке и начинается с символа #.
Обобщенный формат директивы препроцессора:
#define - определение макроса или препроцессорного идентификатора; #include - включение текста из файла;
#undef - отмена определения макроса или идентификатора (препроцессорного); #if - проверка условия-выражения;
#ifdef - проверка определенности идентификатора; #ifndef - проверка неопределенности идентификатора; #else - начало альтернативной ветви для #if; #endif - окончание условной директивы #if;
#elif - составная директива #else/#if;
#line - смена номера следующей ниже строки;
#error - формирование текста сообщения об ошибке трансляции; #pragma - действия, предусмотренные реализацией;
#- пустая директива.
#define идентифиêатор строêа_замещения
Директива может размещаться в любом месте обрабатываемого текста, а ее действие в обычном случае распространяется от точки размещения до конца текста. Директива, во-первых, определяет идентификатор как препроцессорный. В результате работы препроцессора вхождения идентификатора, определенного командой #define, в тексте
программы заменяются строкой замещения, окончанием которой обычно служит признак конца той "физической" строки, где размещена команда #define. Символы пробелов, помещенные в начале и в конце строки замещения, в подстановке не используются.
Предусмотренные директивой #define препроцессорные замены не выполняются внутри строк, символьных констант и комментариев, т.е. не распространяются на тексты, ограниченные кавычками ("), апострофами (') и разделителями (/*, */).
Исходный текст |
Результат препроцессорной обработки |
#define begin { |
|
#define end } |
|
void main() |
void main( ) |
begin |
{ |
операторы |
операторы |
end |
} |
Цепочка подстановок. Åñëè â строке_замещения команды #define в качестве отдельной лексемы встречается препроцессорный идентификатор, ранее определенный другой директивой #define, то выполняется цепочка последовательных подстановок. В качестве примера рассмотрим, как можно определить диапазон (RANGE) возможных значений любой целой переменной типа int в следующей программе:
#include <limits.h>
#defineRANGE |
((INT_MAX) |
- (INT_MIN)+1) |
int RANGE_T |
= RANGE/8; |
|
После вставки текста из <limits.h> получаем следующий код:
#define INT_MAX |
32767 |
|
#define |
INT_MIN |
-32768 |
#define |
RANGE |
((INT_MAX) - (INT_MIN) +1) |
int RANGE_T = RANGE/8;
Последовательные преобразования:
#define RANGE ((32767)-(-32768)+l) int RANGE_T = RANGE/8;
int RANGE_T = ((32767)-(-32768)+1)/8;
Включение текстов из файлов
Для включения текста из файла используется команда #include, имеющая три формы записи: #include < èìÿ_ôàøà > /* Имя в угловых скобках */
#include "имя_файла" /* Имя в кавычках */
#include имя_макроса./* Макрос, расширяемый до обозначения файла */
ãäå имя_макроса - это введенный директивой #defme препроцессорный идентификатор либо макрос, при замене которого после конечного числа подстановок будет получена последовательность символов <имя_файла> ëèáî "имя_файла".
Существует правило, что если имя_файла - в угловых скобках, то препроцессор разыскивает файл в стандартных системных каталогах.
Åñëè имя_файла заключено в кавычки, то вначале препроцессор просматривает текущий каталог пользователя и только затем обращается к просмотру стандартных системных каталогов.
Условная компиляция
#define PRINT_DEBUG #ifdef PRINT_DEBUG
printf ( " Отладочная печать ");
#endif
Макроопределение с параметрами
#define имя(списоê_параметров) строêа_замещения
Для обращения к макросу используется конструкция вида:
имя_маêроса (списоê_арãументов)
В списке аргументы разделены запятыми. Каждый аргумент - препроцессорная лексема. Классический пример макроопределения:
#define max(a, b) (a < b ? b : а)
В тексте программы макровызов max(X, Y)
Будет заменен выражением (X < Y ? Y : X) а использование конструкции max(Z, 4)
приведет к (Z < 4 ? 4 : Z)