Menu

Стандартная библиотека C: карта заголовков, которые стоит знать

Что даёт каждый стандартный заголовок — stdio.h, stdlib.h, string.h, math.h, time.h, ctype.h, limits.h, stdbool.h, stdint.h и assert.h — с коротким рабочим примером на каждый.

На этой странице есть исполняемые редакторы: меняйте, запускайте и сразу видите результат.

Язык C крошечный: типы, операторы, управляющие конструкции, функции, указатели. Он не умеет ни печатать, ни читать файл, ни сравнить строку, ни выделить память. Всё это — стандартная библиотека: набор заголовков, который поставляет каждая соответствующая стандарту реализация.

Эта страница — карта. Каждый раздел говорит, для чего нужен заголовок, показывает один короткий рабочий пример и указывает на более подробную страницу там, где она есть.

stdio.h — ввод и вывод

Заголовок, который вы подключаете первым почти в каждой программе. В нём живут printf и scanf, тип FILE и функции работы с файлами, а также более безопасные построчные функции ввода.

Самое необходимое: printf, fprintf, sprintf, snprintf для вывода; scanf, fscanf, sscanf, fgets, getchar для ввода; fopen, fclose, fread, fwrite, fseek для файлов. Подробнее — в printf, scanf и работе с файлами.

Одно правило стоит унести с собой: никогда не используйте gets(). Он никак не может узнать размер вашего буфера и был удалён из стандарта в C11. Замена — fgets(buf, sizeof buf, stdin).

stdlib.h — утилиты общего назначения

Сборная солянка: память, преобразования, случайные числа, управление процессом, сортировка.

Главное: malloc, calloc, realloc, free (см. динамическую память); atoi, atof, strtol, strtod для преобразований — предпочитайте семейство strto*, которое умеет сообщать об ошибке там, где atoi молча возвращает 0; rand и srand (см. случайные числа); exit, abort, getenv, system; а также qsort/bsearch.

string.h — строки и блоки памяти

Строки в C — это массивы char, заканчивающиеся '\0', и каждая операция над ними есть вызов функции.

Две привычки не дают этому заголовку превратиться в источник переполнений буфера: всегда знайте размер приёмника и помните, что strcmp возвращает 0 при равенстве — if (strcmp(a, b)) истинно, когда строки различаются. Функции для строк подробно разбирают более безопасные приёмы со strncpy/snprintf.

math.h — математика

sqrt, pow, fabs, floor, ceil, round, fmod, семейства тригонометрических и логарифмических функций, INFINITY и NAN.

Это единственный заголовок, которому может понадобиться флаг компоновщика: в Linux добавьте -lm в конец команды компиляции, иначе компоновщик сообщит "undefined reference to sqrt". Полный обзор — в математических функциях.

time.h — часы и даты

Два смещения в struct tm ловят всех: tm_year отсчитывается от 1900 года, а tm_mon нумеруется с нуля. time(NULL) к тому же обычно служит зерном для srand.

ctype.h — классификация символов

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

Полный набор: isalpha, isdigit, isalnum, isspace, isupper, islower, ispunct, isxdigit, isprint, плюс toupper и tolower.

Обратите внимание на приведение (unsigned char). Эти функции определены для значений, представимых как unsigned char, плюс EOF; обычный char на большинстве систем знаковый, поэтому байт больше 127 приходит отрицательным числом и вызов становится неопределённым поведением. Приведение ничего не стоит и снимает целый класс проблем.

И предпочитайте их самодельным проверкам. c >= '0' && c <= '9' случайно работает, но isdigit(c) говорит о том, что вы имеете в виду, и остаётся корректным везде.

limits.h и float.h — границы типов

Насколько большим может быть int на этой машине? Эти заголовки отвечают на вопрос, и именно поэтому переносимый код спрашивает, а не предполагает.

INT_MAX — это способ проверить переполнение до того, как оно произойдёт, и это важно, потому что знаковое переполнение — неопределённое поведение, а не обёртывание, которое можно проверить постфактум.

stdbool.h и stdint.h — типы получше

До C99 в C не было логического типа. <stdbool.h> его даёт:

bool, true и false — это макросы для _Bool, 1 и 0, но они делают намерение очевидным. (В C23 они стали ключевыми словами, и заголовок больше не нужен.)

<stdint.h> даёт типы с гарантированной разрядностью — незаменимые для форматов файлов, сетевых протоколов и всего встраиваемого, где «int, наверное, 32-битный» недостаточно хорошо:

Макросы вида PRId32 из <inttypes.h> разворачиваются в правильный спецификатор printf для каждого типа фиксированной ширины на текущей платформе — это и есть переносимый способ их печатать, ведь %d подходит для int32_t на одних системах и не подходит на других.

assert.h — проверка ваших предположений

assert(expr) не делает ничего, когда выражение истинно, и аварийно завершает программу с сообщением, когда оно ложно.

Компиляция с -DNDEBUG убирает все проверки, так что в релизной сборке они ничего не стоят. В этом же и предупреждение: никогда не помещайте побочный эффект внутрь assert. assert(read_next() > 0) в релизной сборке вообще перестаёт читать, и получившийся баг проявляется только в продакшене.

Проверки предназначены для ваших ошибок — для условий, которые должны быть невозможны, если код корректен. Плохой ввод пользователя — не повод для assert; это if и сообщение об ошибке.

Остальное, кратко

  • <stddef.h>size_t, ptrdiff_t, NULL, offsetof
  • <stdarg.h> — функции с переменным числом аргументов, механика, стоящая за printf
  • <errno.h>errno плюс perror и strerror, чтобы сообщить, почему вызов не удался
  • <signal.h> — обработка сигналов, например Ctrl-C
  • <setjmp.h> — нелокальные переходы; редко бывают правильным ответом
  • <locale.h>, <wchar.h>, <wctype.h> — локали и широкие символы
  • <stdnoreturn.h>, <stdalign.h>, <threads.h>, <stdatomic.h> — дополнения C11

Две привычки делают библиотеку приятной в использовании. Читайте man-страницу, а не угадывайте сигнатуру — man 3 strtol на macOS и Linux авторитетен и быстр. И проверяйте возвращаемые значения: malloc, fopen и strtol все сообщают о неудаче, а программа, которая их игнорирует, ломается гораздо позже и гораздо менее понятным образом.

Часто задаваемые вопросы

Что такое стандартная библиотека C?

Это набор функций, типов и макросов, которые предоставляет каждая соответствующая стандарту реализация C, сгруппированных примерно в 30 заголовков. Он покрывает ввод и вывод (<stdio.h>), память и преобразования (<stdlib.h>), строки (<string.h>), математику (<math.h>), время, классификацию символов и пределы числовых типов. В самом языке C нет ни встроенного ввода-вывода, ни работы со строками — всё это отсюда.

В чём разница между stdio.h и stdlib.h?

<stdio.h> — это ввод и вывод: printf, scanf, fopen, fgets, FILE. <stdlib.h> — это утилиты общего назначения: malloc и free, atoi и strtol, rand и srand, exit, qsort, bsearch. Типичная программа подключает оба.

Для чего нужен ctype.h?

Он классифицирует и преобразует отдельные символы: isdigit, isalpha, isalnum, isspace, isupper, islower, ispunct, плюс toupper и tolower. Использовать их вместо самописных сравнений вроде c >= '0' && c <= '9' понятнее и корректно для любой локали и любой кодировки.

Нужно ли что-то линковать, чтобы использовать стандартную библиотеку C?

Нет, с одним исключением — математическими функциями. Стандартная библиотека C линкуется автоматически, но в Linux реализации из <math.h> лежат в отдельной библиотеке, так что sqrt и компании требуют -lm в конце команды компиляции. Всему остальному нужен только правильный #include.

Coddy programming languages illustration

Учитесь программировать с Coddy

НАЧАТЬ