Поможем написать учебную работу
Если у вас возникли сложности с курсовой, контрольной, дипломной, рефератом, отчетом по практике, научно-исследовательской и любой другой работой - мы готовы помочь.
Если у вас возникли сложности с курсовой, контрольной, дипломной, рефератом, отчетом по практике, научно-исследовательской и любой другой работой - мы готовы помочь.
Заголовочные файлы, директива #include
Заголовочные файлы C могут использоваться для объявления глобальных переменных, констант, описания пользовательских типов данных и в качестве библиотек подпрограмм. Заголовочный файл (h-файл, header-файл) подключается к программе директивой #include и размещается после этой директивы. Имя системного h-файла, входящего в комплект поставки компилятора, должно быть заключено между парами знаков “меньше”, “больше”, например: #include <stdio.h>, #include <conio.h>. Имя пользовательского h-файла, хранящегося в одной папке с исходным текстом программы, должно быть заключено между парами двойных кавычек, например:
#include “mysuper.h”. Поэтому треугольные скобки используются при подключении заголовочных файлов, входящих в стандартную поставку компилятора, а кавычки для подключения дополнительных заголовочных файлов, например, разработанных самим программистом.
Любая C-программа должна содержать хотя бы одну директиву. Так, для реализации ввода/вывода должна присутствовать директива: #include <stdio.h> Файл stdio.h (standard input/output header) содержит необходимую нформацию о средствах ввода/вывода информации:
Директивы #include могут размещаться в любом месте программы до точки входа (функции main), но из соображений улучшения читаемости программы и уменьшения вероятности ошибок программиста, рекомендуется размещать директивы единым блоком в начале программы.
Механизм работы директивы: встретив #include, препроцессор подставляет вместо этой директивы текст, хранящийся в текстовом файле имя_файла. Например, пусть созданы заголовочный файл sample.h и файл с исходным текстом sample.с:
Листинг 3. Иллюстрация работы директивы #include: а) текст заголовочного файла sample.h; б) текст исходного файла программы sample.с, подключающий заголовочный файл sample.h. в) текст программы sample.с после работы препроцессора: текст, содержащийся в sample.h вставляется вместо строки #include "sample.h". Именно текст (в) будет обрабатываться компилятором.
В листинге 3 проиллюстрирован механизм работы #include. На практике h-файлы не используются для разрыва тела программы, т.к. это крайне негативно сказывается на читаемости. На практике, заголовочные файлы чаще всего используются для описания прототипов функций, тела которых хранятся в подключаемых к программе библиотеках, объявления констант, глобальных переменных и описания макросов.
Именно так используются заголовочные файлы стандартной библиотеки C, поставляемой с компилятором языка. Тела функций хранятся в виде объектного кода в библиотеках, которые подключаются к пользовательской программе по умолчанию, но чтобы использовать эти функции, программист должен подключить соответствующий заголовочный файл, содержащий объявление прототипа функции, необходимые константы и макросы.
Заголовочные файлы могут использоваться и для хранения текстов функций, хотя хранение функций в скомпилированном виде в библиотеке предпочтительнее.
Стандартная библиотека C
Стандартная библиотека C содержит 15 библиотек, прототипы функций, макросы и глобальные переменные, которые описаны в заголовочных файлах.
Таблица 1
Заголовочные файлы стандартной библиотеки C.
Перечисленные 15 заголовочных файлов должен содержать любой компилятор, соответствующий стандарту ANSI С. Кроме того, различные компиляторы могут содержать в своей стандартной поставке дополнительные библиотеки и заголовочные файлы.
Одним из преимуществ языка C является наличие значительного количества дополнительных библиотек различного назначения, распространяемых, в частности, посредством сети Internet под различными (в т.ч. и бесплатными) лицензиями.
Константы и макросы, директива #define
Команды препроцессора служебные слова, предваряемые префиксом # не компилируется в машинные коды. Они предназначены лишь для совершения некоторых действий перед компиляцией исходного текста. Например, команда препроцессора, #define NAME expression указывает компилятору, что перед компиляцией нужно заменить по всему тексту программы идентификатор NAME на выражение expression. Чаще всего в таком виде макроопределение (англ. macrodefinition, macros) #define используется для определения констант, например: #define PI 3.1415 определяет константу PI, которую можно использовать везде, где допускается использование числовой константы 3.1415.
Директива #define служит для замены часто использующихся констант, ключевых слов, операторов или выражений некоторыми идентификаторами. Идентификаторы, заменяющие текстовые или числовые константы, называют именованными константами. Идентификаторы, заменяющие фрагменты программ, называют макроопределениями, причем макроопределения могут иметь аргументы.
Директива #define имеет две синтаксические формы:
#define идентификатор текст
#define идентификатор (список параметров) текст
Эта директива заменяет все последующие вхождения идентификатора на текст. Такой процесс называется макроподстановкой. Текст может представлять собой любой фрагмент программы на СИ, а также может и отсутствовать. В последнем случае все экземпляры идентификатора удаляются из программы.
Пример:
#define WIDTH 80
#define LENGTH (WIDTH+10)
Эти директивы изменят в тексте программы каждое слово WIDTH на число 80, а каждое слово LENGTH на выражение (80+10) вместе с окружающими его скобками.
Скобки, содержащиеся в макроопределении, позволяют избежать недоразумений, связанных с порядком вычисления операций. Например, при отсутствии скобок выражение t=LENGTH*7 будет преобразовано в выражение t=80+10*7, а не в выражение t=(80+10)*7, как это получается при наличии скобок, и в результате получится 780, а не 630.
Прятать "магические числа", такие как 300 и 20, внутрь программы - это неудачная практика; они дают мало информации тем, кто, возможно, должен будет разбираться в этой программе позднее, и их трудно изменять систематическим образом. К счастью в языке "C" предусмотрен способ, позволяющий избежать таких "магических чисел".
Используя конструкцию #DEFINE , вы можете в начале программы определить символическое имя или символическую константу, которая будет конкретной строкой символов. Впоследствии компилятор заменит все не заключенные в кавычки появления этого имени на соответствующую строку. Фактически это имя может быть заменено абсолютно произвольным текстом, не обязательно цифрами.
#DEFINE LOWER 0 /* LOWER LIMIT OF TABLE */
#DEFINE UPPER 300 /* UPPER LIMIT */
#DEFINE STEP 20 /* STEP SIZE */
MAIN () /* FAHRENHEIT-CELSIUS TABLE */
{
INT FAHR;
FOR (FAHR =LOWER; FAHR <= UPPER; FAHR =FAHR + STEP)
PRINTF("%4D %6.1F\N", FAHR, (5.0/9.0)*(FAHR-32));
}
Величины LOWER, UPPER и STEP являются константами и поэтому они не указываются в описаниях. Символические имена обычно пишут прописными буквами, чтобы их было легко отличить от написанных строчными буквами имен переменных. отметим, что в конце определения не ставится точка с запятой. Так как подставляется вся строка, следующая за определенным именем, то это привело бы к слишком большому числу точек с запятой в операторе FOR .
Во второй синтаксической форме в директиве #define имеется список формальных параметров, который может содержать один или несколько идентификаторов, разделенных запятыми. Формальные параметры в тексте макроопределения отмечают позиции, на которые должны быть подставлены фактические аргументы макровызова. Каждый формальный параметр может появиться в тексте макроопределения несколько раз.
При макровызове вслед за идентификатором записывается список фактических аргументов, количество которых должно совпадать с количеством формальных параметров.
Пример:
#define MAX(x,y) ((x)>(y))?(x):(y)
Эта директива заменит фрагмент
t=MAX(i,s[i]);
на фрагмент
t=((i)>(s[i])?(i):(s[i]);
Как и в предыдущем примере, круглые скобки, в которые заключены формальные параметры макроопределения, позволяют избежать ошибок связанных с неправильным порядком выполнения операций, если фактические аргументы являются выражениями.
Например, при наличии скобок фрагмент
t=MAX(i&j,s[i]||j);
будет заменен на фрагмент
t=((i&j)>(s[i]||j)?(i&j):(s[i]||j);
а при отсутствии скобок - на фрагмент
t=(i&j>s[i]||j)?i&j:s[i]||j;
в котором условное выражение вычисляется в совершенно другом порядке.
Макросы допускают использование параметров. При использовании в программе такие макросы расширяются на этапе предобработки, т.е. в их текст подставляются заданные в программе значения параметров, и этим текстом заменяется идентификатор макроса в тексте программы. Параметры перечисляются при объявлении макроса через запятую в скобках после его идентификатора.
#include <stdio.h>
#define BIT_SET(X,N) (X)|=1<<(N) //Объявление макроса с параметрами
void main(void){
int M=0, Flags=0;
BIT_SET(Flags, M+2); //Установить 2-ой бит переменной Flags
printf(“\nFlags=%i”, Flags);
}
Листинг 1. Объявление и использование макроса с параметрами.
Макрос BIT_SET устанавливает в переменной X бит номер N в 1, независимо от его начального состояния.
Нужно обратить внимание, что в теле макроса его параметры заключены в скобки. Это рекомендуется делать всегда во избежание логических арифметических ошибок. Например, если бы скобок не было, то макрос из листинга 1 расширился бы в Flags|=1<<M+2 (M=0). Т.е. приоритет выполнения арифметических операций был бы нарушен, что привело бы к логической ошибке результат был бы неверным.
Таким образом, несмотря на внешнее сходство с функциями, макросы являются не более чем средством автоматической, обработки исходного текста программы перед компиляцией. Например, допустимо, хотя и бессмысленно, даже такое использование макроопределения:
#include <stdio.h>
#define ENTRY void main(void){
int a,b;
ENTRY
a=5;
b=2;
printf(“\na+b=%i”, a+b);
}
Листинг 2. Пример использования макроопределения.
Чаще всего макросы используют для реализации компактных арифметических выражений. По сравнению с функциями макросы могут дать некоторый выигрыш в быстродействии программ, т.к. при вызове функции расходуется процессорное время на сохранение в стеке параметров и адреса возврата, а также переходы на точку входа в функцию и адрес возврата. Очевидно также, что при оптимизации программы по размеру макросы проигрывают функциям.
Рекомендуется использовать в именах макросов все заглавные литеры, это позволит “с первого взгляда” отличить макрос от функции или переменной.
Директива #undef
Директива #undef используется для отмены действия директивы #define. Синтаксис этой директивы следующий: #undef идентификатор
Директива отменяет действие текущего определения #define для указанного идентификатора. Не является ошибкой использование директивы #undef для идентификатора, который не был определен директивой #define.
Пример:
#undef WIDTH
#undef MAX
Эти директивы отменяют определение именованной константы WIDTH и макроопределения MAX.