Тема 2. Библиотеки функций

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

Библиотеки подключаются при помощи директивы препроцессора #include. После директивы препроцессора указывается имя библиотеки или имя заголовочного файла библиотеки. Имя заключается в угловые скобки (для стандартных библиотек) или в двойные кавычки (для остальных библиотек).

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

#include <math.h>

А если библиотека располагается в том же каталоге, что и приложение (например библиотека mylib), то подключение библиотеки будет выглядет следующим образом:

#include "mylib.h"

В угловых скобках или в двойных кавычках указывается имя специального заголовочного файла (расширение .h образовано от английского слова header – заголовок). В заголовочных файлах приводятся прототипы функций, а реализация, обычно, размещается в файле с таким же именем, но расширение меняется на .c

Стандартные библиотеки

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

Список некоторых стандартных библиотек функций

Заголовочный файл Содержимое заголовочного файла
<ctype.h> Содержит прототипы функций, проверяющих различные характеристики символов, а также позволяющих выполнять преобразования символов.
<errno.h> Содержит макросы, полезные для сообщений об ошибках.
<float.h> Содержит пределы значений для чисел с плавающей точкой в системе
<limits.h> Содержит пределы значений для целочисленных чисел в системе
<locale.h> Содержит прототипы функций и другую информацию, которая позволяет изменять работу программы и параметры окружения в соответствии с указанными локальными (в смысле региона, страны) настройками: кодировка символов, представление чисел и т.д.
<math.h> Содержит прототипы математических функций.
<signal.h> Содержит прототипы функций и макросы для обработки различных условий, которые могут возникать во время работы программы.
<stdarg.h> Определяет макросы обработки списка параметров функции, для которой неизвестно число параметров и их тип.
<stddef.h> Содержит общие определения типов, используемых Си для выполнения некоторых вычислений.
<stdio.h> Содержит прототипы функций ввода/вывода и информацию, используемую ими.
<stdlib.h> Содержит прототипы функций преобразования чисел в текст и текста в число, прототипы функций размещения памяти, генерации случайных чисел и других сервисных функций.
<string.h> Содержит прототипы функций обработки строк.
<time.h> Содержит прототипы функций и типы данных для функций управления временем и датой.

Библиотеки пользователя и заголовочные файлы

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

Макросы препроцессора

Существуют два типа макросов: макрос-объект(object-like macro) и макрос-функция(function-like macro), оба типа объявляются с помощью директивы #define. Рассмотрим сначала макросы-объекты. Объявляются они как:
#define ИМЯ_МАКРОСА [замещающий текст]
Всё, что идёт после имя макроса до конца строки является замещающим текстом. При помощи макросов-объектов часто определяются константы или часто встречающиеся последовательности переменных и аврифметических операторов:


Однако следует помнить, что макрос это просто подстановка а не переменная, то есть везде где встречается символ N при трансляции программы символ заменяется на его то что в определении идет после имени, то есть в данном случае на число 10. С одиночным символом это не страшно, но при использовании выражения может получиться не верный результат. Например, если на каждом шаге цикла надо не только прибавлять значение i, но и увеличивать получившееся значение вдвое, то приведенный ниже код даст ошибочный результат:

Второй вид макросов — это макро-функции (function-like macros). Определяются они с помощью той-же директивы #define, после которой (сразу без пробелов) в круглых скобках идёт список разделённых запятыми аргументов:

Важным моментом является то, что делитель x также заключен в скобки. Посмотрим, что будет если его не заключать в скобки...


Видно, что во втором случае результат не верный. Все объясняется тем, что макрос препроцессора это просто подстановка, а не функция. То есть при компиляции в строке 21 мы получаем следующее выражение:

val = (a + b + c)/(a+b+c)

А во втором случае (строка 24) получаем:

val = (a + b + c)/a+b+c

то есть периметр делится на длину стороны a, а затем к результату деления прибавляются длины сторон b и c.