Стандартная библиотека C или libc — это стандартная библиотека для языка программирования C , как указано в стандарте ISO C. [1] Начиная с исходного стандарта ANSI C , он был разработан одновременно со спецификацией POSIX библиотеки C , которая является его расширенной версией. [2] [3] Поскольку ANSI C был принят Международной организацией по стандартизации , [4] стандартная библиотека C также называется библиотекой ISO C.
Стандартная библиотека C предоставляет макросы , определения типов и функции для таких задач, как обработка строк , математические вычисления, обработка ввода/вывода, управление памятью и ряд других служб операционной системы .
Интерфейс прикладного программирования (API) стандартной библиотеки C объявлен в ряде заголовочных файлов . Каждый файл заголовка содержит одно или несколько объявлений функций, определений типов данных и макросов.
После длительного периода стабильности три новых файла заголовков ( iso646.h
, wchar.h
, и wctype.h
) были добавлены вместе с Нормативным дополнением 1 (NA1), дополнением к стандарту C, ратифицированному в 1995 году. Были добавлены еще шесть файлов заголовков ( complex.h
, fenv.h
, inttypes.h
, stdbool.h
, stdint.h
и ). tgmath.h
с C99 , версией стандарта C, опубликованной в 1999 году, и еще пятью файлами ( stdalign.h
, stdatomic.h
, stdnoreturn.h
, threads.h
и uchar.h
) с C11 в 2011 году. Всего теперь существует 29 файлов заголовков:
Три файла заголовков ( complex.h
, stdatomic.h
и threads.h
) являются условными функциями, поддержка которых реализациями не требуется.
В стандарт POSIX добавлено несколько нестандартных заголовков C для специфичных для Unix функций. Многие нашли свой путь к другим архитектурам. Примеры включают fcntl.h
и unistd.h
. Ряд других групп используют другие нестандартные заголовки — в библиотеке GNU C есть alloca.h
, а в OpenVMS есть такая va_count()
функция.
В Unix-подобных системах авторитетная документация API предоставляется в виде страниц руководства . В большинстве систем страницы руководства по функциям стандартной библиотеки находятся в разделе 3; раздел 7 может содержать несколько более общих страниц, посвященных основным концепциям (например, man 7 math_error
в Linux ).
Unix-подобные системы обычно имеют библиотеку C в форме общей библиотеки , но файлы заголовков (и набор инструментов компилятора) могут отсутствовать в установке, поэтому разработка C может быть невозможна. Библиотека C считается частью операционной системы Unix-подобных систем; Помимо функций, определенных стандартом C, он включает в себя другие функции, являющиеся частью API операционной системы, например функции, указанные в стандарте POSIX . Функции библиотеки C, включая стандартные функции ISO C, широко используются программами и рассматриваются так, как если бы они были не только реализацией чего-то на языке C, но и де-факто частью интерфейса операционной системы. Unix-подобные операционные системы обычно не могут работать, если библиотека C удалена. Это справедливо для приложений, которые связаны динамически, а не статически. Далее само ядро (по крайней мере, в случае с Linux) работает независимо от каких-либо библиотек.
В Microsoft Windows основные системные динамические библиотеки ( DLL ) предоставляют реализацию стандартной библиотеки C для компилятора Microsoft Visual C++ v6.0; Стандартная библиотека C для более новых версий компилятора Microsoft Visual C++ предоставляется каждым компилятором индивидуально, а также в виде распространяемых пакетов. Скомпилированные приложения, написанные на C, либо статически связываются с библиотекой C, либо связываются с динамической версией библиотеки, которая поставляется с этими приложениями, а не предполагается, что они присутствуют в целевых системах. Функции в библиотеке C компилятора не рассматриваются как интерфейсы к Microsoft Windows.
Существует множество реализаций библиотеки C, поставляемых как с различными операционными системами, так и с компиляторами C. Вот некоторые из популярных реализаций:
Некоторые компиляторы (например, GCC [7] ) предоставляют встроенные версии многих функций стандартной библиотеки C; то есть реализации функций записываются в скомпилированный объектный файл , и программа вызывает встроенные версии вместо функций из общего объектного файла библиотеки C. Это уменьшает накладные расходы на вызовы функций, особенно если вызовы функций заменяются встроенными вариантами, и допускает другие формы оптимизации (поскольку компилятор знает характеристики потока управления встроенных вариантов), но может вызвать путаницу при отладке (например, , встроенные версии не могут быть заменены инструментальными вариантами).
Однако встроенные функции должны вести себя как обычные функции в соответствии с ISO C. Основной смысл заключается в том, что программа должна иметь возможность создавать указатель на эти функции, взяв их адрес, и вызывать функцию с помощью этого указателя. Если два указателя на одну и ту же функцию получены в двух разных единицах перевода в программе, эти два указателя должны сравниваться равными; то есть адрес получается путем разрешения имени функции, которая имеет внешнюю (в масштабе всей программы) связь.
В FreeBSD [8] и glibc, [9] некоторые функции, такие как sin(), не связаны по умолчанию и вместо этого включены в математическую библиотеку libm . Если какой-либо из них используется, компоновщику необходимо дать директиву -lm
. POSIX требует, чтобы компилятор c99 поддерживал -lm
и чтобы функции, объявленные в заголовках math.h
, complex.h
были fenv.h
доступны для связывания, если -lm
указано, но не указывается, связаны ли функции по умолчанию. [10] musl удовлетворяет этому требованию, помещая все в одну библиотеку libc и предоставляя пустую библиотеку libm. [11]
Согласно стандарту C, макросу __STDC_HOSTED__
должно быть присвоено значение 1 , если реализация размещена на хосте. Размещенная реализация имеет все заголовки, определенные стандартом C. Реализация также может быть автономной , что означает отсутствие этих заголовков. Если реализация является автономной , она должна быть определена __STDC_HOSTED__
как 0 .
Некоторые функции стандартной библиотеки C печально известны наличием уязвимостей переполнения буфера и, как правило, способствуют программированию с ошибками с момента их принятия. [a] Наиболее критикуемым пунктам являются:
strcpy()
и strcat()
, из-за отсутствия проверки границ и возможного переполнения буфера, если границы не проверяются вручную;printf()
семейство подпрограмм, предназначенных для порчи стека выполнения , когда строка формата не соответствует заданным аргументам. Этот фундаментальный недостаток создал целый класс атак: атаки на форматную строку ;gets()
и scanf()
семейство процедур ввода-вывода из-за отсутствия (любой или простой) проверки длины ввода.За исключением крайнего случая с gets()
, всех уязвимостей безопасности можно избежать, введя вспомогательный код для управления памятью, проверки границ, проверки ввода и т. д. Это часто делается в виде оболочек, которые делают стандартные библиотечные функции более безопасными и простыми в использовании. Это восходит к книге Б. Кернигана и Р. Пайка «Практика программирования», авторы которой обычно используют оболочки, которые выводят сообщения об ошибках и завершают программу в случае возникновения ошибки.
Комитет ISO C опубликовал технические отчеты TR 24731-1 [12] и работает над TR 24731-2 [13], чтобы предложить принятие некоторых функций с проверкой границ и автоматическим выделением буфера соответственно. Первый встретил резкую критику с некоторой похвалой, [14] [15] второй получил неоднозначные отзывы. Несмотря на это, TR 24731-1 был реализован в стандартной библиотеке Microsoft C, и ее компилятор выдает предупреждения при использовании старых «небезопасных» функций.
Подпрограмму strerror()
критикуют за то, что она небезопасна для потоков и уязвима к условиям гонки .
Обработка ошибок функций стандартной библиотеки C непоследовательна и иногда сбивает с толку. Согласно странице руководства Linux math_error
: «Текущая (версия 2.8) ситуация с glibc запутана. Большинство (но не все) функций вызывают исключения при ошибках. Некоторые также устанавливают errno . Некоторые функции устанавливают errno , но не вызывают исключения. Очень немногие функции не делают ни того, ни другого». [16]
Исходный язык C не содержал встроенных функций, таких как операции ввода-вывода, в отличие от традиционных языков, таких как COBOL и Fortran . [ нужна цитация ] Со временем сообщества пользователей C поделились идеями и реализациями того, что сейчас называется стандартными библиотеками C. Многие из этих идей в конечном итоге были включены в определение стандартизированного языка C.
И Unix , и C были созданы в лабораториях Bell Laboratories компании AT&T в конце 1960-х — начале 1970-х годов. В 1970-е годы язык C становился все более популярным. Многие университеты и организации начали создавать собственные варианты языка для собственных проектов. К началу 1980-х годов стали очевидны проблемы совместимости между различными реализациями языка C. В 1983 году Американский национальный институт стандартов (ANSI) сформировал комитет для установления стандартной спецификации C, известной как « ANSI C ». Кульминацией этой работы стало создание в 1989 году так называемого стандарта C89. Частью полученного стандарта стал набор программных библиотек , названный стандартной библиотекой ANSI C.
POSIX , как и SUS , определяют ряд подпрограмм, которые должны быть доступны помимо тех, которые есть в базовой стандартной библиотеке C. Спецификация POSIX включает файлы заголовков, среди прочего, для многопоточности , работы в сети и регулярных выражений . Они часто реализуются вместе с функциональностью стандартной библиотеки C с различной степенью близости. Например, glibc реализует такие функции, как fork
Within libc.so
, но до того, как NPTL был объединен с glibc, он представлял собой отдельную библиотеку с собственным аргументом флага компоновщика. Часто эта функциональность, определенная POSIX, рассматривается как часть библиотеки; базовая библиотека C может быть идентифицирована как библиотека C ANSI или ISO .
BSD libc — это расширенная версия стандартной библиотеки POSIX, поддерживаемая библиотеками C, включенными в операционные системы BSD, такие как FreeBSD , NetBSD , OpenBSD и macOS . BSD libc имеет некоторые расширения, которые не определены в исходном стандарте, многие из которых впервые появились в версии 4.4BSD 1994 года (первая, которая получила широкое развитие после выхода первого стандарта в 1989 году). Вот некоторые расширения BSD libc:
sys/tree.h
– содержит реализацию красно-черного дерева и дерева отображения [17] [18]sys/queue.h
— реализации связанного списка , очередей , хвостовой очереди и т. д. [19] [20]fgetln()
– определено в stdio.h
. Это можно использовать для чтения файла построчно. [21] [22] [23]fts.h
– содержит некоторые функции для обхода файловой иерархии [24] [25]db.h
– некоторые функции для подключения к базе данных Беркли [26] [27]strlcat()
и strlcpy()
– безопасные альтернативы для strncat()
и strncpy()
[28] [29] [30] [31] [32]err.h
– содержит некоторые функции для печати форматированных сообщений об ошибках [33] [34]vis.h
– содержит vis()
функцию. Эта функция используется для отображения непечатаемых символов в визуальном формате. [35] [36] [37]Некоторые языки включают функциональность стандартной библиотеки C в свои собственные библиотеки. Библиотеку можно адаптировать, чтобы она лучше соответствовала структуре языка, но операционная семантика остается неизменной. Язык C++ , например, включает в себя функциональность стандартной библиотеки C в пространстве имен std
(например, std::printf
, std::atoi
, std::feof
), в заголовочных файлах с именами, похожими на имена C ( cstdio
, cmath
, cstdlib
и т. д.). Другими языками, в которых используются аналогичные подходы, являются D , Perl , Ruby и основная реализация Python , известная как CPython . В Python 2, например, встроенные файловые объекты определяются как «реализованные с использованием stdio
пакета C» [38] , так что ожидается, что доступные операции (открытие, чтение, запись и т. д.) будут вести себя так же, как и соответствующие функции C. В Rust есть крейт под названием libc , который позволяет использовать несколько функций C, структур и других определений типов. [39]
Стандартная библиотека C мала по сравнению со стандартными библиотеками некоторых других языков. Библиотека C предоставляет базовый набор математических функций, манипуляций со строками, преобразования типов , а также файлового и консольного ввода-вывода. Он не включает стандартный набор « типов контейнеров », таких как стандартная библиотека шаблонов C++ , не говоря уже о полных наборах инструментов графического пользовательского интерфейса (GUI), сетевых инструментах и изобилии других функций, которые Java и .NET Framework предоставляют в стандартной комплектации. Основное преимущество небольшой стандартной библиотеки состоит в том, что обеспечить рабочую среду ISO C намного проще, чем с другими языками, и, следовательно, портировать C на новую платформу сравнительно легко.
gets()
был создан еще в 1988 году.