Лекция 2. Функции и многофайловые программы в Си (1153709), страница 3
Текст из файла (страница 3)
Общий видописания макро с параметрами:#define Имя_Макро(Список_Параметров) Тело_МакроПример:#define square(x) ((x)*(x)) /*макро с формальным параметром*/13... int i,j; ...j=square(i); /*расширяется в j=((i)*(i)) */Аргумент макро необходимо заключать в круглые скобки, чтобывместо формального параметра можно было подставлять выражение.Пример "неприятности" при отсутствии скобок:#define square(x) x*x /*макро с форм. параметром без скобок*/... int i,j,l;...j=square(i+l);/*расширяется в j=i+l*i+l -нет перемножения аргументов*/Макро с параметрами похожи на процедуры - но только на первый взгляд! Отличия макро от процедур: обращение к процедуре генерирует в объектном модуле команду безусловного перехода с возвратом и передачу параметров, обращение к макро приводит к вставкев исходную программу тела макро; поэтому применение макро увеличивает код программы, но экономит время выполнения (за счет отсутствия пересылки параметров).Обычно не рекомендуется использовать макро вместо процедур,так как при применении макро отсутствует всякий контроль правильности подстановки параметров.2.3.3.
Директива #include включения файловДиректива #include позволяет включать в исходную программулюбые текстовые файлы. Формы директивы:#include <СпецификацияФайла>#include "СпецификацияФайла"#include ИмяМакроПервая форма директивы предполагает, что подключается заголовочный файл с расширением .h (т. е файл шаблонов стандартныхфункций); он будет отыскиваться в стандартных директориях (текущей или указанных в Main Menu/Options/Directories/Include Files).Вторая форма указывает, что поиск файла осуществляется помаршруту, заданному в " "; если файл там не найден, то просматриваются стандартные директории.14Третья форма предполагает, что существует макроопределение,заменяющее Имя_Макро на спецификацию файла в угловых скобкахили двойных кавычках.2.3.4.
Директивы условной компиляцииОни позволяют производить выборочную компиляцию программы. Самый простой вид такой директивы:#if ЛогическоеВыражениеTRUE-секция#elseFALSE-секция#endifПример: В зависимости от того, определен ли макрос NAME, регулируется значение макроса BUF.#ifdef NAME#define BUF 135#else#define BUF 80#endif2.4.
Многофайловые СИ-программы2.4.1. Структура программы на Си. Область действия переменныхПрограмма на Си состоит из одного или нескольких файлов(текстовых). Исходные текстовые файлы программы содержат описания функций, одна из которых обязательно main, прототипы (шаблоны) функций, директивы препроцессора и описания глобальных переменных, констант, типов (т.
е. описания глобальных имен, отличных отфункций).Локальное имя - описанное внутри функции; может использоваться только в этой функции. Глобальное имя - описанное вне функций; доступно в части программы от точки описания до конца файла.Существует термин область действия имени. Это часть программы, в которой понятие, обозначенное этим именем, доступно. Таким образом, область действия локального имени - блок функции, в15которой оно объявлено; глобального - от места объявления до концафайла.Если требуется воспользоваться глобальным именем вне области его действия (в области от начала файла до объявления имениили в другом файле), то нужно повторить объявление имени, предварив его описателем extern.
Объявление extern не предусматриваетраспределение памяти; оно лишь делает нужное имя доступным.Пример.файл 1файл 2float a;extern float a;int i;f3()main (){a=...;{int i;extern float b;}a=...; b=...;extern int c;}f4()float f1(){ a=...{int i; a=...}}f5()float b; {a=...;float f2()}{int i;a=...; b=...;int c;}...Глобальная переменная а может использоваться во всехфункциях файла 1, т. к. она описана в самом начале файла 1; онатакже доступна всем функциям файла 2, потому что объявлениеextern float a стоит в начале файла 2.Глобальная переменная i файла 1 недоступна ни одной функцииэтого файла, так как каждая функция имеет локальную переменную i.Описание int i приводит к выделению ячейки памяти под переменнуюi каждый раз при входе в блок {...},где стоит это описание; при выходеиз блока эта ячейка освобождается.
Локальные i доступны только вблоке своей функции, а глобальная i - во всем файле 1, за исключением этих функций.Глобальная переменная b файла 1 может использоваться вфункции f2, т. к. объявлена до описания f2. В функциях, описанных16выше объявления b, эта переменная недоступна. Объявление externfloat b в блоке функции main, позволяет этой функции использовать b;тем не менее, для f1 переменная b остается недоступной.В файле 2 вместо двух объявлений int c и extern int c можно было бы оставить только int c, поместив его на место extern int c.Рекомендации.1. По возможности описания глобальных переменных, в томчисле и extern, следует ставить в начало файла.2.
Не стоит делать глобальными промежуточные переменные(например, i в программе, приведенной ниже), потому что:1) это делает подпрограмму менее универсальной, так какприводит к появлению непонятного пользователю "стыка"- промежуточной глобальной переменной;2) приводит к неэкономному расходованию памяти, так какглобальные переменные занимают память в течение всего времени работы программы.Однако допустимо использование глобальных переменных дляпередачи данных между подпрограммами (если не требуется подстановка параметров). Так, если бы в примере 1 п.2.2.4 требовалось обработать одну матрицу, то можно было бы использовать функции безпараметров:#include <stdio.h>#include <math.h>void masout();void matrin();void minmatr();float a[3][5],min[3];void main(){matrin(); minmatr(); masout();}void minmatr (){int i,j;for (i=0; i<3; i++){min[i]=a[i][0];for (j=1;j<5; j++)17if (a[i][j]<min[i])min[i]=a[i][j];}}void matrin(){int i,j;printf(" Введите матpицу pазмеpом 3*5 \n");for (i=0;i<3;i++)for (j=0;j<5;j++)scanf("%f",*(a+i)+j);}void masout(){int i;printf(" Миним.элементы стpок матpицы \n");for (i=0;i<3;i++)printf("%4.1f ",min[i]); printf("\n");}Замечания.1.
Невозможно было бы в приведенном примере использование глобальных матриц, если с помощью одной процедуры надо было обработать несколько матриц. Тогда один формальный параметр надо было бы последовательно заменять на несколько фактических.2. В объявлении extern невозможна инициализация.3. Имена функций - это особые глобальные имена. Они видимы извсех файлов одного проекта. Однако шаблон функции действуеттолько в пределе одного файла.
Поэтому приходится помещать в каждый файл программы директивы include препроцессора, подключающие прототипы библиотечных функций, неоюходимых в этом файле.4. Компилятор Си по описаниям глобальных переменных не толькодает им место в памяти, но и обнуляет их. Локальные переменные приописании не обнуляются; их значения считаются неопределенными(если, конечно, они не заданы инициализацией, вводом или присваиванием).182.4.2. Время жизни и класс памяти переменныхКроме понятия области действия имени, рассматриваетсяблизкое к нему (но не совпадающее!) понятие времени жизни (существования) имени.
По времени жизни имена делятся на статические(существуют все время выполнения программы), автоматические(существуют во время выполнения функции, в которой описаны),динамические (получают место в памяти с помощью операторов динамического распределения памяти).Статическим переменным компилятор выделяет ячейки памятив фиксированных сегментах данных.
Автоматические переменныерасполагаются в стеке. Существуют автоматические переменные,описанные как register; они хранятся во внутренних регистрах процессора; эти переменные их мы рассматривать не будем.Статические переменные - это глобальные переменные и переменные, описанные как static; последние доступны только функции, вкоторой описаны, но существуют (занимают память) во время выполнения всей программыАвтоматические переменные - это локальные переменные, необъявленные static, (и переменные типа register).Статические локальные переменные часто используются программами управления ресурсами - например, для подсчета числа обращений к программе. Ниже приведен пример использования локальной статической переменной:f(); /*шаблон*/main(){...f();f();...;f();/*переменная i будет накапливать число обращений*/}/* к f*/f(){static int i=0;/*инициализация работает один раз при первом входе в блок */... i=i+1;}Класс памяти характеризует область действия, время жизни ирасположение в памяти переменных.
Возможно следующее располо19жение в памяти: стек, сегмент данных или регистры процессора, динамическая память.Ниже приведена простейшая схема оперативной памяти, используемой системой Borland C++[4].Верхние адресастек (локальные переменные)динамическая памятьНижние адресасегмент данных (статическая память)код программыОписатели класса памятиauto - для переменных, действующих в пределах блока; обычнопринимается по умолчанию.register - тоже, что и auto, но для регистров процессора.static - для описания статических переменных.extern - делает доступными глобальные переменные, расширяяих область действия.Характеристики классов памяти приведены в таблице :Таблица 4КлассВремя жизни Область действияМесто в памятипамяти в программеautoвременноблокстекregister временноблокрегистры процессор4staticпостоянноблоксегмент памятиexternпостояннофайл, программасегмент памяти4Обычно используют для локальных переменных20.