Н.В. Вдовикина, И.В. Машечкин, А.Н. Терехин, В.В. Тюляева - Программирование в ОС UNIX на языке Си, страница 4
Описание файла
PDF-файл из архива "Н.В. Вдовикина, И.В. Машечкин, А.Н. Терехин, В.В. Тюляева - Программирование в ОС UNIX на языке Си", который расположен в категории "". Всё это находится в предмете "операционные системы" из 3 семестр, которые можно найти в файловом архиве МГУ им. Ломоносова. Не смотря на прямую связь этого архива с МГУ им. Ломоносова, его также можно найти и в других разделах. .
Просмотр PDF-файла онлайн
Текст 4 страницы из PDF
Пример описания и определения функции в новой и в старой нотациях:/*прототип */int f(char);.../* определение */int f(char c){/*…тело функции…*/}/*прототип */int f();.../* определение */int f(c)char c;{/*…тело функции…*/}новая нотациястарая нотацияВ языке Си аргументы всегда передаются в функцию «по значению». То же касается и возврата значения из функции.Задача 1. Написать функцию, суммирующую два вещественныхзначения в двух вариантах: сумма – возвращаемое значение функциии сумма – параметр функции.. . .double sum1(double,double);/* прототипфункции sum1*/void sum2(double,double,double*); /* прототипфункции sum2*/main(){ double a1=2.5, u;int a2=3;u=sum1(a1,a2);printf(“u=%f\n”,u); /* u=5.5 */sum2(a1,a2,&u);printf(“u=%f\n”,u); /* u=5.5 */}double sum1(double x,double y){ return x+y; }void sum2(double x,double y,double *z){ *z=x+y; }Список параметров переменной длиныСписок формальных параметров функции может быть переменной длины – в этом случае он заканчивается “, …” и должен со20держать хотя бы один обычный именованный параметр.
Примеромтакой функции является функция печати printf, описанная в заголовочном файле <stdio.h>:int printf(const char *format, …);Для работы с параметрами, количество и тип которых заранеене известны, используется механизм макросов из файла стандартнойбиблиотеки <stdarg.h>. В теле функции должна быть описана переменная типа va_list, которая будет содержать информацию осписке неименованных аргументов. Чтобы получить доступ к неименованным параметрам через эту переменную, необходимо прежде всего обратиться к макросу va_start.
Макрос va_startполучает два параметра: упомянутую переменную типа va_list ипоследний именованный параметр функции. Он инициализирует переменную типа va_list так, чтобы она указывала на первый неименованный параметр:int f(p1, p2, ...){va_list parg;va_start(parg, p2);/* p2 – последнийименованный параметр функции f */int i = va_arg(parg, int);...va_end(parg);}Далее, каждое обращение к макросу va_arg выдает очереднойпараметр и передвигает указатель (переменную типа va_list) наследующий параметр. Макросу va_arg передают два аргумента: переменную типа va_list, предварительно проинициализированнуюс помощью va_start, и имя типа ожидаемого параметра. Таким об-разом, программа сама должна определить, каков тип очередногоожидаемого ею аргумента из неименованного списка.
Макросva_end нужен для корректного завершения работы с переменнойтипа va_list.Поскольку функции не известны ни типы передаваемых неименованных параметров, ни их количество, то для корректной работы с такими параметрами может использоваться различная дополнительная информация. Например, как в случае функции printf,параметр format полностью определяет типы и число последующихпараметров. Другой способ – передавать через фиксированный параметр количество неименованных параметров, если их типы предполагаются известными.Задача 2. Написать функцию, возвращающую максимальный из полученных ею фактических параметров (типа unsigned int).#include <stdio.h>21#include <stdarg.h>unsigned int unsgn_max(unsigned int count, ...);/* Число неименованных параметров передается черезпараметр count, который не учитывается при поискемаксимума.
*/main(){printf(“max = %d\n”,unsgn_max (3, 10, 20, 30));}unsigned int unsgn_max(unsigned int count, ...){va_list ap;unsigned int res = 0, cur;int i;va_start(ap, count);for(i=1; i<=count; i++)if(res < (cur = va_arg(ap,unsigned int)))res = cur;va_end(ap);return res;}Общая структура программыПрограмма может размещаться как в одном, так и в нескольких файлах, содержать одну или несколько функций, одна из которых считается головной (main) - с нее начинается выполнение программы. Определение каждой функции должно полностью размещаться в одном файле, при этом файл может содержать несколькоопределений различных функций.В соответствии со структурой программы переменные обладают следующими качествами:• видимость переменной (область видимости);• существование переменной (область существования).Область видимости переменныхОбласть видимости переменной определяет часть исходноготекста программы, из любой точки которой доступна данная переменная.С точки зрения видимости можно выделить следующие группы переменных:22• видимые в пределах блоков (локальные)4,• видимые в пределах файла,• видимые в пределах программы.Для переменных, определенных в начале любого блока, областью видимости является весь этот блок.
В случае вложенных блоков переменные, определенные внутри вложенного блока, “перекрывают” переменные с такими же именами, определенные в объемлющем блоке (и так для любой степени вложенности). Например:main(){ int x = 1;if(x>0){ int x = 2;printf(“x = %d\n”, ++x); /*выводит: x = 3 */}printf(“x = %d\n”, x); /*выводит: x = 1 */}Переменные, определенные внутри функции, “перекрывают” формальные параметры с теми же именами 5:int f(int f){int f = 1;…}Переменные, определенные вне блоков (т.е., фактически, внетела какой-либо функции), доступны с точки определения до концафайла. Если на такую переменную нужно сослаться до того, как онаопределена, необходимо ее описание со спецификатором extern,например:int x;main(){extern int y;x = y = 10;printf(“x=%d, y=%d\n”,x,y); /* x=10, y=10 */}…int y;блоками являются: составной оператор, определение (тело) функции, условный оператор и переключатель switch, оператор цикла (вложенным блоком для него является также телоцикла)5Следует заметить, что в приведенном ниже примере коллизии имени функции f с именем формального параметра или с переменной f, определенной внутри функции, не будет из-заразличия областей видимости.423В файле вне функций не может встречаться несколько определений переменных (возможно, разных типов) с одним и тем же именем:int x;main(){...}float x;/* ошибка: повторное определение x */Указание static, примененное к нелокальной переменной илифункции, ограничивает область их видимости концом файла 6.
Прочие же функции и нелокальные переменные могут быть доступны издругого программного файла.Если используемая переменная определена в другом программном файле, она также должна быть описана со спецификатором extern. При таком описании переменной память под нее не отводится, а только декларируется тип переменной, что позволяеткомпилятору осуществлять проверки типизации.Примечание. Переменные, определенные внутри блока, как иформальные параметры функций, "перекрывают" переменные с темиже именами, видимые в пределах файла и в пределах программы.Область существования переменныхОбласть существования переменной – это множество всех точек программы, при приходе управления на которые переменнаясуществует, т.е. для нее выделена память. В отличие от области видимости, про область существования можно сказать, что это понятие«времени выполнения» С этой точки зрения можно выделить двегруппы переменных:1.
Статические переменныеПеременные, являющиеся статическими, существуют на всемпротяжении работы программы. Память под эти переменные выделяется на этапе редактирования внешних связей и загрузки программы, тогда же происходит и инициализация статических переменных (следует отметить, что инициализатором для статическойпеременной может служить только константное выражение, а приотсутствии инициализатора статические переменные по умолчаниюинициализируются нулем).
Правила определения статических переменных различаются в зависимости от конкретного места программы, в котором это определение встретилось. Для определения статиЗдесь возникает некая терминологическая путаница, поскольку, как будет рассказанониже, ключевое слово static еще используется для определения статических (с точки зренияобласти существования) переменных, а в данном контексте с помощью static задаются границы области видимости.624ческой переменной, локализованной в блоке, используется ключевоеслово static, например:int max; /*статическая переменная вне блока*/int f(int param){static int min; /* статическая переменная,определенная внутри блока */…}Основным свойством статических переменных, определенныхвнутри блока, является сохранение их значений при выходе из блока.
Например:#include <stdio.h>void print_a();main(){ int i;for(i=0; i<5; i++)print_a();}в результате напечатается:aaaaa=====12345void print_a(){static int a = 1;printf(“a = %d\n”, a++);}Все переменные, определенные вне функций, являются статическими.2.
Автоматические переменныеАвтоматическими переменными являются все переменные определенные внутри блока (функции) и не являющиеся статическими.Автоматические переменные существуют на протяжении работыблока, в котором они определены, включая блоки, вложенные в данный. Выделение памяти под автоматические переменные и их инициализация осуществляется каждый раз при входе в блок. Инициализация для автоматических переменных, фактически, эквивалентнаприсваиванию, т.е. в качестве инициализирующего выражения может выступать любое выражение, которое может стоять в правойчасти оператора присваивания.
При отсутствии инициализатора начальное значение по умолчанию для автоматических переменных неопределено.25#include <stdio.h>void print_a();main(){ int i;for(i=0; i<5; i++)print_a();}в результате напечатается:aaaaa=====11111void print_a(){int a = 1;printf(“a = %d\n”, a++);}При выходе из блока память, выделенная под автоматическиепеременные, освобождается.3. Регистровые переменныеВ качестве одного из доступных программисту средств оптимизации язык Си предлагает возможность использования так называемых регистровых переменных. Это достигается за счет использования квалификатора register в определении переменных, чтоуказывает компилятору, что данную переменную в целях ускоренияпрограммы имеет смысл разместить на регистрах, однако компилятор может проигнорировать это указание.
Квалификатор registerможет применяться только к автоматическим переменным и формальным параметрам функций. Независимо от того, была ли переменная, описанная с квалификатором register, действительно размещена на регистрах или нет (что программисту неизвестно), длянее не определено понятие адреса (т.е. не определена операция &).26int f(int a){int i;register int r;...r = a--;if(r){return f(r);}return r;}…a=2адрес возвратасохраненный fp(*)сохраненные регистрыauto переменная iauto переменная rmain(){...int b = f(2);...}(если ее не удалосьразместить на регистрах)a=1адрес возвратасохраненный fpсохраненные регистрыauto переменная iauto переменная r(если ее не удалосьразместить на регистрах)(*) – стековый кадр –непрерывная область памятистека, используемая функциейдля своей работыfp (frame pointer) – указательстекового кадраРис.1Стековый кадрОбычно размещение в памяти автоматических переменных,как и передача параметров и возврат значений из функций, реализуются с использованием стека.