Системные вызовы и библиотеки Unix




Скачать 152.79 Kb.
Дата08.07.2016
Размер152.79 Kb.

Введение

Системные вызовы и библиотеки Unix


Граница между системным и прикладным программированием достаточно условна. Любой программист так или иначе вынужден пользоваться сервисами операционной системы. Эти сер­висы могут быть скрыты от программиста средой исполнения языка высокого уровня или раз­личными «кроссплатформенными» библиотеками и фреймворками. Однако абстракции, пред­ставляемые средой исполнения и библиотеками неидеальны, они «протекают». Главные направления таких протечек — это, в первую очередь, производительность и процесс отладки.

Когда программа работает не так, как запланировано — это может происходить как из-за ошиб­ки в библиотеке, так и, чаще, из-за ошибочного использования библиотеки — в процессе отлад­ки часто приходится спускаться на низкий уровень и анализировать происходящее не в терми­нах объектов и шаблонов ЯВУ, а в терминах указателей и системных вызовов. Поэтому знаком­ство с системным программированием может оказаться полезным и для тех, кто собственно си­стемным программированием заниматься не планирует.

С точки зрения программиста на относительно низкоуровневом языке, таком, как C, сервисы ОС выглядят как набор функций, предоставляемых системными библиотеками, и собственно си­стемные вызовы.

Системные вызовы — это обращения к ядру операционной системы. В ОС, поддерживающих виртуальную память, пользовательский код не может самостоятельно исполнять ряд операций, в том числе — выполнять операции ввода-вывода, обращаться к структурам данных ОС и к памя­ти других процессов. Системный вызов включает в себя переход в системный (привилегирован­ный) режим работы процессора, передачу управления ядру и копирование параметров в па­мять ядра. Ядро проверяет наличие прав на исполнение запрошенной операции и, если права есть, исполняет саму операцию.

Главные функции, выполняемые системными вызовами, включают в себя ввод-вывод (в том числе доступ к файловой системе и к сети), межпроцессное взаимодействие и доступ к настрой­кам системы и глобальным данным, например, к показаниям системных часов.

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

Задачи функций библиотеки отличаются большим разнообразием. Некоторые из функций, та­кие, как буферизованный ввод-вывод (известный также как библиотека стандартного ввода-­вывода) пытаются сократить количество системных вызовов. Системные вызовы — относи­тельно более дорогая операция, чем простой вызов функции, поэтому, например, считывать дан­ные из файла или с терминала по одному символу считается нежелательным. Библиотека предо­ставляет буфер в пользовательской памяти, к которому программа может обращаться удобным для нее образом, например, считывая по одному символу или по строкам. Когда буфер опустеет или, наоборот, заполнится, библиотека исполняет системный вызов и считывает или записывает новую порцию данных.

Другие библиотечные функции предоставляются для удобства или для совместимости со стары­ми версиями ОС или для обеспечения соответствия стандартам.


Системы семейства Unix


Границы семейства Unix точно не определены. В это семейство входят операционные системы, архитектура и/или доступные пользователю сервисы которых, в основном, унаследованы от оригинальной ОС Unix, разработанной Д.Томпсоном и К.Ритчи в начале 1970х в Bell Laboratories (в то время — исследовательское подразделение компании AT&T).

В первом приближении, ОС семейства Unix можно разбить на следующие группы:



  1. Системы, наследующие авторские права на код и архитектурные решения оригинального Unix. Из поддерживаемых на 2012 год, это ряд систем, основанных на Unix Sysvem V Release 3, в первую очередь IBM AIX и HP HP/UX, а также системы, основанные на Unix System V Release 4, в первую очередь, Oracle Solaris.

  2. Системы, разработанные без использования кода, авторские права на который принадлежат или принадлежали AT&T, но, в основном, воспроизводящие архитектуру традиционного Unix. Это ветви BSD Unix (FreeBSD, OpenBSD, NetBSD), Minix, Linux. BSD Unix первона­чально использовал код AT&T Unix v6/7, опубликованный на условиях public domain, но в начале 1990х ветви BSD были переписаны, чтобы избавиться от соответствующего кода и претензий к нарушению авторских прав. Minix и Linux никогда не содержали кода AT&T

  3. ОС специального назначения с оригинальной (чаще всего, микроядерной) архитектурой, при разработке которых ставилась цель обеспечить определенную степень совместимость с Unix, главным образом, для облегчения переноса средств разработки (компиляторов, отладчиков и др.) и сетевых средств. К этой категории следует отнести и Apple OS X и Apple iOS. Однако, наиболее распространенные ОС из этой категории — это ОС реаль­ного времени, такие, как QNX и VxWorks. По-видимому, эти ОС долгое время наиболее рас­пространенными ОС семейства Unix, так как они широко используются в массовых встраи­ваемых устройствах (автомобильных компьютерах, контроллерах медицинского и бытового оборудования и т. д.). Возможно, к 2012 году, из-за распространения портативных устройств под управлением Android и других встраиваемых и специализированных компьютеров под Linux (например, сетевых маршрутизаторов), положение уже изменилось и на данный мо­мент лидером является Linux. Точно определить численность специализированных компью­теров под управлением конкретной ОС затруднительно, так как сводной статистики по этому вопросу в открытом доступе нет.

  4. Строго говоря, эти ОС не следует считать принадлежащими к семейству Unix, но в некото­рых обзорах их также включают в это семейство. Это ОС оригинальной архитектуры, разви­вавшиеся независимо от Unix, но в настоящее время, обеспечивающие достаточную степень совместимости со стандартами POSIX и x/Open. Некоторые из этих ОС оказались достаточно совместимы, чтобы пройти сертификацию x/Openи получить право на использование торго­вой марки UNIX. Примерами таких ОС являются IBM ОS/390, IBM z/OS, HP OpenVMS.

Более подробное описание истории семейства Unix и различий между основными ветвями се­мейства приведено в приложении «История Unix».

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


Стандарты


За время существования семейства Unix был предпринят ряд попыток стандартизовать систем­ные интерфейсы, чтобы облегчить перенос программного обеспечения между разными система­ми семейства. В настоящее время, наиболее влиятельный из стандартов — это Single Unix Specification, документ, принятый и поддерживаемый консорциумом Open Group (http://www.opengroup.org). Этот документ имеет также статус стандарта IEEE Std 1003 (POSIX) и ISO/IEC 9945.

Стандарт SUS/POSIX специфицирует API (Application Programming Interface), то есть интер­фейс, доступный прикладному программисту. Этот стандарт обеспечивает совместимость на уровне исходного кода на языках C/C++. Адаптация программы к другой реализации стандарта мо­жет потребовать (и, обычно, требует) перекомпиляции. Так, API определяет минимальный на­бор полей в структурах данных, но не указывает, может ли структура содержать другие поля и в каком порядке эти поля должны быть размещены в структуре; API допускает реализацию функции как в виде, собственно, функции языка C, так и в виде препроцессорного ма­кроса.

Практика показала, что стандарт SUS/POSIX обеспечивает достаточно большую свободу в вы­боре методов реализации, так что даже многие ОС, не входящие в семейство Unix, например, IBM z/OS или HP OpenVMS, декларируют ту или иную степень совместимости с POSIX.

Кроме API, существует более низкий уровень спецификации системных интерфейсов, называе­мый ABI (Application Binary Interface). ABI включает в себя:



  • спецификацию системы команд

  • «соглашение о вызовах», то есть способ передачи параметров функциям, способ переда­чи кода возврата функции, формат стекового кадра и спискок регистров, которые обяза­ны сохраняться при вызовах

  • формат исполняемых файлов и разделяемых библиотек

  • структуру виртуального адресного пространства

  • способ исполнения системных вызовов и передачи параметров

  • номера системных вызовов и списки параметров каждого вызова

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

  • численные значения различных параметров, например, размещение битовых флагов или номера кодов ошибок

ОС, предоставляющие совместимые ABI, не требуют перекомпиляции пользовательских про­грамм, то есть обеспечивают бинарную совместимость. Обычно, бинарная совместимость обес­печивается в пределах одной линии ОС: новые версии бинарно совместимы со старыми. ОС Unix System V, в том числе Solaris, поддерживают стандарт iBCS (Intel Binary Compatibility Standart).

В этом курсе мы будем изучать стандарт SUS/POSIX на примере его реализации Unix System V Release 4, например, Solaris.


Системные вызовы


Системные вызовы - это интерфейс между пользовательским процессом и операционной систе­мой. Существуют системные вызовы для:

. Ввода/вывода: например, read, write и ioct

. Управления файлами: например, chmod, unlink и mknod

. Доступа к системным данным: например, getuid и getpid

. Управления процессами и их синхронизации: например, signal, wait и semop

. Управления памятью: например, brk, sbrk и mmap

В Unix, все системные вызовы имеют функции-«обертки» в стандартной библиотеке языка C, так что системные вызовы можно вызывать как обычные функции языка C. Многие из систем­ных вызовов принимают аргументы; также, многие вызовы возвращают значение. Обычно, воз­вращаемое значение -1 сигнализирует об ошибке. В этом случае, системный вызов (точнее, его функция-обертка) размещает код ошибки в переменной errno (в многопоточных программах, в действительности, это не переменная, а препроцессорный макрос, но этот макрос является lvalue, т. е. ему можно присваивать значения и получать указатель на него). Во многих старых учебниках рекомендуют описывать errno как extern int errno, но для совместимости с многопо­точными программами рекомендуется использовать определение, предоставленное в заголовоч­ном файле .

Переменная errno устанавливается при ошибках; в соответствии со стандартом POSIX, систем­ный вызов имеет право изменять errno при успешном завершении, поэтому при успешном вызо­ве значение errno следует считать неопределенным. По этой же причине, не следует ориентиро­ваться на значение errno для проверки успешности системного вызова.

Многие библиотечные функции, содержащие внутри системный вызов, также устанавливают errno.

Для всех допустимых значений errno в заголовочном файле определены символьные константы, которые соответствуют мнемоническим именам ошибок. В разных Unix-системах номера ошибок могут различаться, поэтому, при анализе значения errno следует использовать эти константы, а не численные значения. Это значительно облегчит адаптацию вашей програм­мы к другим ОС.


Организация системного руководства


Системное руководство Unix доступно из командной строки через команду man(1). При каждом вызове, команда man выдает содержимое указанной страницы руководства, например, команда man man выдает руководство по самой команде man. Существуют также графические програм­мы для просмотра системного руководства, например, xman(1). В системном руководстве описа­ны все системные вызовы, все функции стандартной библиотеки и других библиотек, входящих в поставку системы, все команды, доступные из командной строки и ряд другой информации.

Руководство разделено на пять секций:

1 Команды, доступные из командной оболочки shell (подсекция 1M — команды, требующие административных привилегий)

2 Системные вызовы.

3 Функции и библиотеки. Этот раздел имеет ряд подсекций, в том числе:

3C Библиотечные функции, реализованные на Си или ассемблере, составляющие стандартную библиотеку языка Си. Эти функции содержатся либо в /usr/libc.so (для разделяемых библиотек), либо в /usr/lib/libc.a (для архивных библиотек). В Solaris 9, архивной версии библиотеки libc.a не предоставляется. При компиляции программы на языке C, редактор связей автоматически под­ключает одну из этих библиотек.

3G Библиотечные функции общего назначения. Необходима опция -lgen в командной строке cc для поиска в библиотеке /usr/lib/libgen.so.

3M Математические библиотечные функции, образующие математическую библиотеку. Необ­ходима опция -lm в командной строке компилятора. Объявления этих функций могут быть по­лучены из .

3X Специализированные библиотечные функции. Распределены по нескольким библиотекам. Прочитайте соответствующую страницу Руководства, чтобы определить библиотеку, которая должна быть задана.

4 Форматы файлов, описывает форматы системных файлов. Например, passwd(4) описывает формат файла /etc/passwd, в котором хранится БД учетных записей.

5 Остальные средства. Например, карта символов ASCII на странице ASCII(5), полезные сведе­ния о системном вызове fcntl(2) на FCNTL(5), полезные сведения о системном вызове wait(2) на WSTAT(5), сведения о сигналах на страницах SIGINFO(5) и SIGNAL(5).

Использование системного руководства


Ссылки на системное руководство в тексте учебного пособия, а также и в самом системном ру­ководстве, выглядят так: name(section), где name — имя страницы, а section — номер или назва­ние секции.

Основным средством доступа к системному руководству является команда man(1). Простейший вызов этой команды выглядит так: man ls. Эта форма команды выдает страницу руководства по команде ls(1). Если необходимо указать секцию руководства, в Solaris необходимо использо­вать форму команды man -s 2 read — эта форма команды выдает страницу read(2). Чаще всего, секцию руководства необходимо указывать, когда в разных секциях существуют одно­именные страницы, например, read(1) (комадна shell) и read(2) (системный вызов) или passwd(1) (команда shell для смены пароля) и passwd(4) (формат файла БД учетных записей).

При выводе на терминал, команда man пропускает вывод через фильтр more(1), позволяющий листать текст по страницам, а также искать в тексте строки, используя шаблоны (регулярные выражения).

По умолчанию, прокрутка на одну строку делается нажатием , а прокрутка на страни­цу (на один экран терминала) — нажатием пробела. Перемещение на строку назад делается символом 'b', а на страницу — Ctrl-B. Для поиска необходимо ввести символ /, шаблон для поис­ка и . Для повторного поиска того же шаблона можно ввести /.

Синтаксис шаблона аналогичен шаблонам, используемым командами grep(1) и sed(1), а также многими программистскими редакторами, такими, как vi/vim, emacs, gedit, NetBeans, Eclipse. Большинство символов соответствуют самим себе. Cимвол '.' соответствует любому символу, символ '*' соответствует нулю или более вхождений предыдущего выражения (например, пре­дыдущего символа), '+' - одному или более вхождениям. Выражение в квадратных скобках зада­ет диапазон символов, например, [0-9] соответствует любой десятичной цифре. Точный синтак­сис регулярных выражений, поддерживаемых more(1), может быть найден на странице руко­водства regex(5)

Для выхода из more(1) (при этом команда man также завершается) можно использовать команду 'q' (quit).

По умолчанию, man(1) ищет страницы руководства в каталоге /usr/share/man, где расположены страницы, входящие в стандартную поставку системы. Для просмотра руководства по дополни­тельным пакетам, например, по компилятору SunStudio, может быть необходимо подключить дополнительные каталоги для поиска. Это может быть сделано опцией -M, например, команда man -M /opt/SolarisStudio12.3-solaris-x86-bin/solarisstudio12.3/man cc выдаст руководство по компилятору языка C из пакета SunStudio (точное значение параметра -M должно соответство­вать местоположению пакета SunStudio в вашей системе). Также, вместо параметра -M допол­нительные каталоги можно подключать при помощи переменной среды MANPATH.

Еще одна полезная команда, связанная с man(1) — это команда apropos(1). Эта команда осуще­ствляет поиск по заголовкам страниц руководства. Так, apropos file выводит список всех стра­ниц руководства, в заголовке (точнее, в секции NAME) которых содержится подстрока file.

У ряда Unix-систем, в том числе у Solaris, страницы системного руководства выложены в Ин­тернет в виде веб страниц, у Solaris — на сайте http://docs.oracle.com. При использовании интер­нет-версий, необходимо внимательно следить, соответствуют ли страницы на сайте вашей вер­сии системы. На сайте Oracle доступны руководства от всех версий Solaris, начиная с 2.4.

Формат страницы Руководства


. ЗАГОЛОВОК (TITLE) - обычно имя библиотечной функции или системного вызова

. СЕКЦИЯ (SECTION) - раздел Руководства

. БИБЛИОТЕКА (LIBRARY) - для секции 3, библиотечных функций, например C, S, M, E, X или G.

. ИМЯ (NAME) - имя и краткое описание системного вызова или библиотечной функции (в од­ной строке)

. ИСПОЛЬЗОВАНИЕ (SYNOPSIS) - как вызвать системный вызов/библиотечную функцию. Для функций библиотек языка C и системных вызовов в этой секции указан прототип функции, а также все заголовочные файлы, которые необходимо включить для корректной работы с функ­цией, например, те, где описан прототип функции и типы, используемые этой функцией в каче­стве параметров или кода возврата.

. ОПИСАНИЕ (DESCRIPTION) - описывает работу системного вызова или функции. Часто, самый длинный раздел руководства.

. ВОЗВРАЩАЕМОЕ ЗНАЧЕНИЕ (RETURN VALUE) - как интерпретировать возвращаемый код.

. ОШИБКИ (ERRORS) — для системных вызовов и библиотечных функций, использующих системные вызовы, перечисляет все допустимые значения errno и их значение.

. СМ. ТАКЖЕ (SEE ALSO) - страницы Руководства, имеющие отношение к этой странице.

. АТРИБУТЫ (ATTRIBUTES) — стандарты, которым соответствует функция, а также особен­ности при использовании в многопоточной программе и при работе с длинными файлами (файлами, длина которых превышает 2Гб)

Кроме того, страница Руководства может содержать разделы:

. ПРИМЕРЫ (EXAMPLES)

. ФАЙЛЫ (FILES)

. СООБЩЕНИЯ (DIAGNOSTICS)

. ЗАМЕЧАНИЯ (NOTES)

. (ПРЕДУПРЕЖДЕНИЯ) WARNINGS

. (ОШИБКИ) BUGS

. (ПРОБЛЕМЫ) CAVEATS

Пример страницы Руководства (секция 3)


Библиотечные функции перечислены в Секции 3.

(3C) означает что эта функция размещена в стандартной библиотеке Cи (в /usr/lib/libc.so).

ИМЯ имя функции и краткое описание.

ИСПОЛЬЗОВАНИЕ соответствующий include-файл и объявление функции perror. Объявление говорит, что perror(3C) ничего не возвращает (void) и требует один аргумент. Аргумент должен быть адресом символа, в данном случае - адресом символьной строки, оканчивающейся нуле­вым байтом.

ОПИСАНИЕ работа функции. perror(3C) печатает текст, переданный в качестве аргумента, за­тем двоеточие и пробел, затем сообщение об ошибке по текущему значению errno и перевод строки. Описание сообщений об ошибках можно найти на странице Руководства INTRO(2) и в файле , а также в разделе ERRORS страниц руководства по системным вызовам.

Сообщение об ошибке может быть включено в отформатированную пользователем строку при помощи strerror(3C). Эта функция возвращает указатель на сообщение об ошибке по значению errno. Эта функция использует внешнюю переменную errno как индекс во внешнем массиве, на­зываемом sys_errlist[]. Это массив указателей на различные сообщения об ошибках, связанных со значением errno. Эти две переменные описываются на странице STRERROR(3C).

Пример: printf("A %s caused the error\n", strerror(errno));


Пример страницы Руководства (Секция 2)


ИМЯ название системного вызова и однострочное описание

ИСПОЛЬЗОВАНИЕ необходимые include-файлы. time(2) возвращает значение типа time_t, представляющее время в секундах с 1 января 1970 года, 00:00:00 UTC. time требует один

параметр, адрес time_t. Тип time_t представляет собой typedef, определенный в . Если параметр ненулевой, возвращаемое значение также запоминается по адресу, заданному в качестве параметра.

ОПИСАНИЕ указывает, что time(2) возвращает значение time_t, соответствующее текущему времени, измеренному в секундах с 1 января 1970 года, 00:00:00 UTC.

time(2) возвращает -1 в случае неуспеха. Некоторые системные вызовы могут по различным причинам завершаться неудачно. Многие страницы Руководства перечисляют коды ошибок, начинающиеся с буквы 'E', которые обозначают конкретную причину неуспеха.

На 32-битных платформах, time_t определен как 32-битное целое. 19 января 2038 года в 03:14:07 UTC 32-битный time_t должен переполниться. Это известно как «Проблема 2038 года». На 64-битных платформах используется 64-битный time_t и этой проблемы не существует. Официаль­ная позиция Oracle состоит в том, что ни одна из 32-битных версий ОС, поддерживаемых Oracle, не имеет ожидаемого срока жизни, достигающего 2038 года, поэтому на 2012 год решения для 32-битных ОС не предлагается.

Поскольку можно предположить, что к 2038 году значительное число встраиваемых и портатив­ных устройств по прежнему будет использовать 32-битные процессоры, можно ожидать появле­ния переходного ABI, аналогичного переходному ABI для использования 64-битного off_t в 32-битных программах (ABI для 64-битного off_t будет обсуждаться в разделе «Системные вызовы ввода-вывода»)ю

ВОЗВРАЩАЕМОЕ ЗНАЧЕНИЕ объясняет значения, возвращаемые при успехе или неуспехе.

СМ. ТАКЖЕ перечисляет функции или системные вызовы, имеющие отношение к данному. stime(2) используется суперпользователем для установки часов. ctime(3C) используется для преобразование значения time(2) в удобный для человека формат.


Примеры использования time(2)


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

. описания и инициализации. Должны быть включены файлы, перечисленные в Руководстве. Они объявляют системный вызов time(2) и описывают typedef time_t. Описаны четыре перемен­ные типа time_t и указатель на time_t. При этом указатель инициализируется.

. нулевое значение параметра time(2) означает, что должно использоваться возвращаемое зна­чение. Под результат не было выделено памяти, и предполагается использовать возвращаемое значение. . инициализированный указатель в качестве аргумента. Время будет сохранено в ячейке памяти, на который указывает переменная tp. Поскольку tp инициализирован, *tp совпа­дает с переменной t2. Кроме того, то же самое значение будет присвоено t3.

. адрес переменной в качестве аргумента. Прочитанное значение системных часов будет поме­щено в переменную типа time_t. Преобразование типа возвращаемого значения в void означает, что возвращаемое значение не будет использоваться.

ПРИМЕРЫ ИСПОЛЬЗОВАНИЯ time(2)


. объявления и инициализации

#include #include time_t t1, t2, t3, t4; time_t *tp = &t2;

. нулевое значение параметра time(2) означает, что должно использоваться возвращаемое значе­ние

t1 = time ( 0 );

. инициализированный указатель в качестве аргумента

t3 = time ( tp );

. адрес переменной в качестве аргумента

(void) time ( &t4 );

Пример страницы Руководства (Секция 3)


В разделе ИСПОЛЬЗОВАНИЕ описано несколько функций.

. Должен быть включен файл .

. ctime, localtime и gmtime все требуют по одному параметру. Это адрес переменной или поля структуры типа time_t. Значение этой переменной может быть установлено обращением к time(2).

- ctime возвращает адрес символа. Это адрес начала символьной строки, завершающейся ну­левым символом. Формат строки не зависим от настроек языка. Для вывода даты и времени на национальном языке необходимо использовать функции strftime(3C) и strptime(3C).

- localtime и gmtime возвращают адрес структуры tm.

Раздел ОПИСАНИЕ описывает возвращаемое значение и элементы структуры tm.

Замечания:

1. localtime сначала вызывает tzset, чтобы получить значение переменной среды TZ. На основа­нии этого значения tzset инициализирует массив указателей на строки tzname и внешние пере­менные timezone и altzone. timezone устанавливается равной разнице времени между UTC и дан­ной временной зоной, измеренному в секундах. Например, в Нью Джерси,

tzname[0] == "EST" и timezone == 5*60*60 tzname[1] == "EDT" и altzone == 4*60*60

2. Поле tm_isdst структуры tm при вызове функций localtime и gmtime устанавливается положи­тельным, если действует сезонное изменение времени, нулевым, если оно не действует, и отри­цательным, если информация недоступна.

3. Внешняя переменная daylight устанавливается положительной, только если в данной TZ ис­пользуется сезонное изменение времени.

4. localtime реализована следующим образом: она вычитает timezone из прочитанного значения time и вызывает gmtime. Раздел ПРОБЛЕМЫ говорит о «перезаписи» содержимого: функции ctime, asctime, localtime и gmtime возвращают указатель на внутренний буфер. Содержимое это­го буфера может быть перезаписано последующим вызовом соответствующих функций.

5. В разделе АТРИБУТЫ указано, что функции ctime, asctime, localtime и gmtime в Solaris 10 возвращают указатели на локальные данные нити, и поэтому являются безопасными для исполь­зования в многопоточной программе (в каждой нити эти функции будут возвращать разные ука­затели). Тем не менее, использование этих функций не рекомендуется, потому что стандарт POSIX не требует, чтобы эти функции были безопасны в многопоточных программах. Рекомен­дуется использовать реентерабельные версии этих функций: localtime_r, gmtime_r и т.д. Также указано, что сами по себе функции безопасны, но прямая модификация переменных timezone, altzone и daylight во время работы этих функций может приводить к непредсказуемым результа­там.

Библиотечная функция mktime(3C) может быть использована для преобразования структуры tm в календарное время (количество секунд с 00:00:00 1 января 1970).

Библиотечная функция difftime(3C) возвращает разницу между двумя календарными временами как double. Эта функция нужна, потому что, в соответствии с требованиями POSIX, для типа time_t может быть не определено основных арифметических операций.


Пример использования time(2) и ctime(3C)


Эта программа демонстрирует использование time(2) и ctime(3C). Она работает следующим об­разом:

9 Определяет переменную now типа time_t.

10 Определяет указатель sp на struct tm.

12 Вызывается time(2). Время в секундах от 00:00:00 UTC 1 января 1970 сохраняется в перемен­ной now.

14 Библиотечная функция ctime(3C) преобразует календарное время в ASCII-строку формата date(1). Адрес, возвращенный этой функцией, используется в качестве параметра printf для печа­ти ASCII-строки.

16 Вызывается библиотечная функция localtime(3C). Эта функция заполняет значениями поля структуры tm.



17-20 Распечатываются значения полей структуры tm.

Файл: ex_time.c ПРИМЕР ИСПОЛЬЗОВАНИЯ time(2) И ctime(2) 1 #include 2 #include 3 #include 4 #include 5 extern char *tzname[]; 6 7 main() 8 { 9 time_t now; 10 struct tm *sp; 11 12 (void) time( &now ); 13 14 printf("%s", ctime( &now ) ); 15 16 sp = localtime(&now); 17 printf("%d/%d/%02d %d:%02d %s\n", 18 sp->tm_mon + 1, sp->tm_mday, 19 sp->tm_year, sp->tm_hour, 20 sp->tm_min, tzname[sp->tm_isdst]); 21 exit(0); 22 }


База данных защищена авторским правом ©uverenniy.ru 2016
обратиться к администрации

    Главная страница