13. Математика
Эта глава содержит информацию относительно функций для выполнения математических вычислений, типа тригонометрических функций. Большинство этих функций имеет прототипы, объявленные в файле "math.h".
Все функции используют аргументы с плавающей запятой и возвращают результаты типа double. В будущем, могут появиться дополнительные функции, которые используют значения long double и float. Например, cosf и cosl были бы версиями функци cos, которые используют аргументы типов float и long double, соответственно. Вы должны избегать использовать эти имена самостоятельно. См. Раздел 1.3.3 [Зарезервированные Имена].
13.1 Ошибки Области и Диапазона
Многие из функций, перечисленных в этой главе определены математически над областью, которая является только подмножеством вещественных чисел. Например, acos функция определена над областью от -1 до 1. Если Вы передаете аргумент одной из этих функций, который не находится в области, на которой она определена, функция устанавливает errno как EDOM, чтобы указать ошибку области. На машинах, которые поддерживают формат ИИЭР (IEEE) с плавающей запятой, также возвращают ошибку EDOM и NaN.
Некоторые из этих функций определены математически, чтобы привести к комплексному значению над частями их областей. Наиболее знакомый пример это квадратный корень отрицательного числа.
Функции в этой главе берут аргументы только с плавающей точкой и возвращают значения соответственно того же типа.
Проблема возникает тогда, когда математический результат функции не может быть представим как число с плавающей запятой. Если величина результата слишком большая, функция устанавливает errno как ERANGE, чтобы указать ошибку диапазона, и возвращает "очень большое значение" (именованое макрокомандой HUGE_VAL) или отрицание (- HUGE_VAL).
Если величина результата является слишком малой, возвращается нулевое значение. В этом случае, errno может быть или не быть установлена как ERANGE.
Единственый полностью надежный способ проверять ошибки области и диапазона состоит в том, чтобы установить errno как 0 прежде чем Вы вызываете математическую функцию и затем проверять errno. Следствие такого использования errno является то, что математические функции не могут быть многократно использованы с проверкой ошибок.
Ни одна из математических функций не генерирует сигналы в результате ошибок диапазона или области. В частности это означает что Вы не будете видеть сигналы SIGFPE, сгенерированные внутри этих функций. (См. Главу 21 [Обработка Сигнала], для получения более подробной информации.)
Это выражение представляющее наибольшее число. На машинах, которые используют, ИИЭР формат с плавающей запятой это значение "бесконечность". На других машинах, это обычно самое большое положительное число, которое может быть представлено.
double HUGE_VAL (макрос)
Значение этой макрокоманды используется как возвращаемое значение из различных математических функций в случаях переполнения.
Для получения более подробной информации см. Раздел A. 5.3.2 [Параметры с плавающей запятой]. В частности макрокоманда DBL_MAX могла бы быть более удобной, чем HUGE_VAL для многих использований отличных от тестирования ошибки в математической функции.
13.2 Тригонометрические Функции
Это знакомые функции sin, cos, и tan. Аргументы всех этих функций измеряются в радианах; помните, что pi радиан равняются 180 градусам.
Математическая библиотека не определяет символическую константу для pi, но Вы можете определять вашу собственную, если Вы нуждаетесь в этом:
Вы можете также вычислять значение pi выражением acos (-1.0).
#define PI 3.14159265358979323846264338327
Эта функция возвращает синус x, где x дан в радианах. Возвращаемое значение находится в диапазоне от -1 до 1.
double sin (double x)
Эта функция возвращает косинус x, где x дан в радианах. Возвращаемое значение находится в диапазоне от -1 до 1.
double cos (double x)
Эта функция возвращает тангенс x, где x дан в радианах.
double tan (double x)
Следующие errno условия ошибки определены для этой функции:
- ERANGE
-
Математически функция tan имеет особенности в точках (2*k+1)*pi/2. Если аргумент x близок к одной из этих особенностей, tan устанавливает errno как ERANGE и возвращает или положительный или отрицательный HUGE_VAL.
13.3 Обратные Тригонометрические Функции
Это обычные arcsin, arccos и arctan функции, которые являются обратными для синуса, косинуса и тангенса, соответственно.
Эта функция вычисляет арксинус x то есть значение, чей синус является x. Значение результата дается в радианах. Математически, имеется бесконечно много таких значений; но фактически возвращаются значения между -pi/2 и pi/2 (включая).
double asin (double x)
Asin устанавливает errno как EDOM, если x находится вне диапазона. Функция арксинуса определена математически только над областью от -1 до 1.
Эта функция вычисляет аркосинус x, то есть значение, чей косинус является x. Значение результата дается в радианах. Математически, имеется бесконечно много таких значений; но фактически возвращаются значения между 0 и pi (включая).
double acos (double x)
Acos устанавливает errno как EDOM, если x находится вне диапазона. Функция аркосинуса определена математически только над областью от -1 до 1.
Эта функция вычисляет арктангенс x то есть значение, чей тангенс является x.
double atan (double x)
Значение результата дается в радианах. Математически, имеется бесконечно много таких значений; но фактически возвращаются значения между -pi/2 и pi/2 (включая).
Это функция арктангенса двух аргументов. Она подобна вычислению арктангенса y/x, за исключением того, что знаки обоих аргументов используются, чтобы определить квадрант результата, и x может быть нулем. Возвращаемое значение дано в радианах и находится в диапазоне от -pi до pi (включительно).
double atan2 (double y, double x)
Если x и y координаты точки в плоскости, atan2 возвращает угол между линией от начала координат до этой точки и осью X. Таким образом, atan2 полезен для преобразования декартовых координат в полярные координаты. (Чтобы вычислять радиальную координату, используйте hypot; см. Раздел 13.4 [Экспоненты и Логарифмы])
Функция atan2 устанавливает errno как EDOM, если и x и y нули и возвращаемое значение не определено.
13.4 Возведение в степень и Логарифмы
Эта функция возвращает значение e (основание натуральных логарифмов) в степени x.
double exp (double x)
Если величина результата слишком большая, чтобы быть представимой функция устанавливает errno как ERANGE.
Эта функция возвращает натуральный логарифм x. exp (log(x)) равняется x, точно в математике и приблизительно в Cи.
double log (double x)
Следующие условия ошибки errno определены для этой функции:
Функция устанавливает EDOM, если аргумент x отрицателен. Функция log определена математически, чтобы возвращать результат только на положительных аргументах.
Функция устанавливает ERANGE, если аргумент - нуль. Log нуля не определен.
Эта функция возвращает логарифм x по основанию 10. Кроме основания , она подобна функции log. Фактически, log10 (x) равняется log (x) / log (10).
double log10 (double x)
Это общая функция возведения в степень, возвращающая base в степени power.
double pow (double base, double power)
Следующие условия ошибки errnoопределены для этой функции:
Функция устанавливает EDOM base, если аргумент отрицателен.
Функция устанавливает ERANGE, если было обнаружено условие переполнения.
Эта функция возвращает квадратный корень x.
double sqrt (double x)
Sqrt устанавливает errno как EDOM, если x отрицателен. Математически, квадратный корень был бы комплексным числом.
Эта функция возвращает кубический корень x. Эта функция определена на всей вещественной оси и поэтому не изменяет переменную errno.
double cbrt (double x)
Эта функция возвращает sqrt (x * x + y * y). (Это длина гипотенузы прямоугольного треугольника со сторонами длины x и y, или расстояние точки (x, y) от начала.) См. также функцию cabs в Разделе 14.3 [Абсолютное значение].
double hypot (double x, double y)
Эта функция возвращает эквивалент значения exp (x) - 1. Оно вычислено точным способом, даже если значение x близко к нулю.
double expm1 (double x)
Эта функция возвращает эквивалент значения log (1 + x). Оно вычислено точным способом, даже если значение x - близко к нулю.
double log1p (double x)
13.5 Гиперболические функции
Функции в этом разделе связаны с экспоненциальными функциями; см. Раздел 13.4 [Экспоненты и Логарифмы].
Эта функция возвращает гиперболический синус x, определенный математически как exp (x) - exp (-x) /.2 Функция устанавливает errno как ERANGE, если значение x слишком большое; то есть если происходит переполнение.
double sinh (double x) (функция)
Функция cosh возвращает гиперболический косинус x, определенный математически как exp (x) + exp (-x) /.2 Функция устанавливает errno как ERANGE, если значение x слишком большое; то есть если происходит переполнение.
double cosh (double x) (функция)
Эта функция возвращает гиперболический тангенс x, чье математическое определение sinh (x) / cosh (x).
double tanh (double x) (функция)
Эта функция возвращает обратный гиперболический синус x, чей гиперболический синус является x.
double asinh (double x) (функция)
Эта функция возвращает обратный гиперболический косинус x, чей гиперболический косинус является x. Если x - меньше чем 1, acosh возвращает HUGE_VAL.
double acosh (double x) (функция)
Эта функция возвращает обратный гиперболический тангенс x, чей гиперболический тангенс является x. Если абсолютное значение x больше или равно 1, atanh возвращает HUGE_VAL.
double atanh (double x) (функция)
13.6 Псевдослучайные Числа
Этот раздел описывает средства GNU для получения ряда псевдослучайных чисел. Сгенерированные числа не совсем произвольные; обычно, они формируют последовательность, которая повторяется периодически, с периодом настолько большим, что Вы можете игнорировать его для обычных целей. Генератор случайных чисел работает, используя всегда значение начального числа, чтобы вычислить следующее случайное число и так далее.
Хотя сгенерированные чисала выглядят непредсказуемо при одном выполнении программы, последовательность чисел точно та же самая и при следующем выполении. Это происходит, потому что начальное число всегда одно то же . Это удобно, когда Вы отлаживаете программу, но неподходит, если Вы хотите, чтобы программа вела себя непредсказуемо. Если Вы хотите действительно случайные числа, а не только псевдослучайными, определяйте начальное число, основываясь на текущем времени.
Вы можете получать повторяющиеся последовательности чисел на машине определенного типа, определяя то же самое начальное значение начального числа для генератора случайных чисел. Не существует никакого стандарта для значения начального числа; то же самое начальное число, используемое в различных библиотеках C или на различных типах CPU , даст Вам различные случайные числа.
Библиотека GNU поддерживает стандартные функции случайного числа ANSI C плюс набор, который происходит от BSD. Мы рекомендуем, чтобы Вы использовали стандартные rand и srand.
Функции Случайного числа ANSI C
Этот раздел описывает функции случайного числа, которые являются частью стандарта ANSI C.
Чтобы использовать эти средства, Вы должны включить заглавный файл "stdlib.h" в вашей программе.
Значение этой макрокоманды - выражение константы integer, которое представляет максимальное возможное значение, возвращенное функцией rand. В библиотеке GNU, это - 037777777, которое является самым большим целым числом со знаком, представимым в 32 битах. В других библиотеках это может быть всего 32767.
int RAND_MAX (макрос)
Функция rand возвращает следующее псевдослучайное число. Значение находится в диапазоне от 0 до RAND_MAX.
int rand () (функция)
Эта функция устанавливает seed как начальное число для нового ряда псевдослучайных чисел.
void srand (unsigned int seed) (функция)
Если Вы вызываете rand перед тем как начальное число было установлен srand, то она использует значение 1 как заданное по умолчанию начальное число.
Чтобы производить случайные числа (не только псевдослучайные), делайте srand(time(0)).
BSD Функции Случайного числа
Этот раздел описывает набор функций для порождения случайного числа, являющиеся дополнением к BSD.
Нет особого преимущества при использовании этих функций с библиотекой GNU C; мы поддерживаем их только для совместимости BSD.
Прототипы для этих функций находятся в " stdlib.h ".
Эта функция возвращает следующее псевдослучайное число. Диапазон возвращенных значений - от 0 до RAND_MAX.
long int random () (функция)
Srandom функция устанавливает начальное число для random. Если Вы обеспечиваете значение начального числа 1, это заставит random воспроизводить набор случайных значений по умолчанию.
void srandom (unsigned int seed) (функция)
Чтобы производить действительно случайные числа (не только псевдослучайные), делайте srandom(time(0)).
Эта функция используется, чтобы инициализировать состояние генератора случайного числа. Аргумент state это массив size байтов, используемый для хранения информации о состоянии. Размер должен быть по крайней мере 8 байтов, а оптимальные размеры - 8, 16, 32, 64, 128, и 256. Больший массив состояния, лучше.
void * initstate (unsigned int seed, void *state, size_t size) (функция)
Возвращаемое значение - предыдущее значение массива информации о состоянии. Вы можете использовать это значение позже как аргумент setstate, чтобы восстановить состояние.
Эта функция восстанавливает информацию о состоянии случайного числа. Аргумент должен быть результатом предыдущего обращения к initstate или setstate.
void *setstate (void *state)
Возвращаемое значение - предыдущее значение массива информации о состоянии. Вы можете использовать это значение позже как аргумент setstate, чтобы восстановить состояние.
14. Арифметические функции низкого уровня
Эта глава содержит информацию относительно функций предназначенных для выполнения базисных арифметических операций, типа разбивания float на целую и дробную части. Эти функции объявлены в заголовочном файле "math.h ".
14.1 "Не Числовые" Значения
Формат ИИЭР с плавающей запятой используемый наиболее современными компьютерами, поддерживает значения, которые являются "не числами". Эти значения называются NaN. Эти значения следуют из некоторых операций, которые не имеют никакого значимого числового результата, типа нуля, деленого на нуль или бесконечности, деления на бесконечность.
Одна примечательная особенность NaN'ов заключается в том, что они не равны себе. Таким образом, x == x может быть 0, если значение x - NaN. Вы можете использовать это, чтобы проверить является ли значение NaN или нет: если оно не равно себе, то это - NaN. Но рекомендуемый способ проверять NaN - isnan функцией (см. Раздел 14.2 [Предикаты на Значениях с Плаваюшей точкой]).
Почти любая арифметическая операция, в которой аргумент является NaN, возвращает NaN.
double NAN (макрос)
Выражение, представляющее значение, которое является "не числом". Эта макрокоманда является расширением GNU, доступное только на машинах, которые поддерживают значения "not a number" то есть на всех машинах поддерживающих формат с плавающей запятой.
Вы можете использовать " #ifdef NAN " чтобы проверить, поддерживает ли машина NaN. (Конечно, Вы должны принять меры, чтобы расширения GNU были видимыми, определяя _GNU_SOURCE, и Вы должны включить " math.h ".)
14.2 Предикаты на Float
Этот раздел описывает некоторые разнообразные функции-тесты double значений. Прототипы для этих функций появляются в "math.h". Это функции BSD, и таким образом доступны, если Вы определяете _BSD_SOURCE или _GNU_SOURCE.
int isinf (double x) (функция)
Эта функция возвращает -1, если x представляет отрицательную бесконечность, 1, если x представляет положительную бесконечность, и 0 иначе.
int isnan (double x) (функция)
Эта функция возвращает значение отличное от нуля, если x - значение " not a number ", и нуль иначе. (Вы можете точно также использовать x!= x, чтобы получить тот же самый результат).
int finite (double x) (функция)
Эта функция возвращает значение отличное от нуля, если x конечен или значение " not a number ", и нуль иначе.
double infnan (int error) (функция)
Эта функция предусмотрена для совместимости с BSD. Другие математические функции используют infnan, чтобы решить, что возвратить в случае ошибки. Аргумент - код ошибки, EDOM или ERANGE; infnan возвращает подходящее значение, чтобы указать ошибку. ERANGE также допустим как аргумент, и соответствует -HUGE_VAL как значение.
В библиотеке BSD, на некоторых машинах, infnan вызывает фатальный сигнал во всех случаях. Библиотека GNU не делает аналогично, потому что это не удовлетворяет спецификации ANSI C.
Примечание Переносимости: функции, перечисленные в этом разделе - расширения BSD.
14.3 Абсолютное значение
Эти функции предусмотрены для получения абсолютного значения (или величины) числа. Абсолютное значение вещественного числа x - x если x положителен, -x, если x отрицателен. Для комплексного числа z, чья вещественная часть является x и чья мнимая часть является y, абсолютное значение - sqrt (x * x + y * y).
Прототипы для abs и labs находятся в " stdlib.h "; fabs и cabs объявлены в " math.h ".
int abs (int number) (функция)
Эта функция возвращает абсолютное значение числа.
Большинство компьютеров использует двоичное дополнение представления integer, в котором абсолютное значение INT_MIN (самый маленький возможный int) не может представляться; таким образом, abs (INT_MIN) не определен.
long int labs (long int number) (функция)
Подобна abs, за исключением того, что и аргумент и результат имеют тип long int а не int.
double fabs (double number) (функция)
Эта функция возвращает абсолютное значение числа с плавающей запятой.
double cabs (struct { double real, imag; } z) (функция)
Функция cabs возвращает абсолютное значение комплексного числа z, чья вещественная часть является z.real и чья мнимая часть является z.imag. (См. также функцию hypot в Разделе 13.4 [Экспоненты и Логарифмы].); значение:
sqrt (z.real*z.real + z.imag*z.imag)
14.4 Функции Нормализации
Функциям, описанные в этом разделе прежде всего обеспечивают способ эффективно выполнить некоторые манипулирования низкого уровня на числах с плавающей запятой, которые представляются, внутренне используя двоичную систему счисления. Эти функции требуются, чтобы реализовать эквивалентное поведение, даже если представление не использует основание системы счисления 2, но конечно они, вряд ли, будут особенно эффективны в тех случаях.
Все эти функции объявлены в " math.h ".
double frexp (double value, int *exponent) (функция)
Frexp функция используется, чтобы разбивать значение числа на нормализованную дробь и экспоненту.
Если значение аргумента value - не нуль, возвращаемое значение value - число степеней двойки, и всегда в диапазоне от 1/2 (включ.) до 1 (исключ.). Соответствующая экспонента сохранена в *exponent; возвращаемое значение, умноженное на 2 возведенное в эту экспоненту, равняется первоначальному значению числа.
Например, frexp (12.8, &exponent) возвращает 0.8 и сохраняет 4 в exponent.
double ldexp (double value, int exponent) (функция)
Эта функция возвращает результат умножения значения числа с плавающей запятой на 2 в степени exponent. (Это может использоваться, чтобы повторно транслировать числа с плавающей запятой, которые были демонтированы frexp.)
Например, ldexp (0.8, 4) Возвращает 12.8.
Следующие функции, которые исходят ИЗ BSD, обеспечивают эквиваленты средств ldexp и frexp:
double scalb (double value, int exponent)
Scalb функция - BSD имя для ldexp.
double logb (double x)
Эта BSD функция возвращает целочисленную часть логарифма x по осн. 2, целочисленное значение представляется в double. Знак x игнорируется. Например, logb (3.5) = 1.0 и logb (4.0) = 2.0.
Когда 2 в этой степени разделена на x, это дает частное между 1 (включ.) и 2 (исключ.).
Если x - нуль, значение - минус бесконечность (если машина поддерживает такое значение), или очень малое число. Если x - бесконечность, значение - бесконечность.
Значение, возвращенное logb на один меньше чем то что frexp сохранил бы в *exponent.
double copysign (double value, double sign) Function
Copysign функция возвращает значение, чье абсолютное значение равно указанному значению, и чей знака противоположен исходному. Это - функция BSD.
14.5 Функции Округления и Остаточного члена
Функции, перечисленные здесь выполняют операции типа округления, усечения, и взятия остаточного члена от деления чисел с плавающей запятой. Некоторые из этих функций преобразовывают числа с плавающей запятой в целочисленные значения. Они все объявлены в " math.h ".
Вы можете также преобразовывать числа с плавающей запятой в integer просто, приводя их к int. Это отбрасывает дробную часть, действительно округляя к нулю. Однако, это работает только, если результат может фактически представляться как int и для очень больших чисел, это невозможно. Функции, перечисленные здесь возвращают результат как double, чтобы обойти эту проблему.
double ceil (double x)
Ceil функция округляет x вверх к самому близкому целому числу, возвращая это значение как double. Таким образом, ceil (1.5) = 2.0.
double floor (double x)
floor функция округляет x вниз к самому близкому целому числу, возвращая это значение как double. Таким образом, floor (1.5) = 1.0, а floor (-1.5) = -2.0.
double rint (double x)
Эта функция округляет x к целочисленному значению согласно текущему режиму округления.
Режим округления значения по умолчанию к самому близкому целому числу; некоторые машины поддерживают другие режимы, но этот не всегда используется если Вы явно выбираете другой.
double modf (double value, double *integer_part)
Эта функция разбивает значение аргумента на целочисленную часть и дробную часть (между -1 и 1, не включ.). Их сумма равняется значению. Каждая из частей имеет тот же самый знак как значение, так что округление целочисленной части - к нулю.
Modf сохраняет целочисленную часть в *integer_part, и возвращает дробную часть. Например, modf (2.5, &intpart) возвращает 0.5 и сохраняет 2.0 в integer_part.
double fmod (double numerator, double denominator)
Эта функция вычисляет остаточный член от деления numerator yf denominator. Специально, возвращаемое значение - numerator - n * denominator, где n - частное numerator/denominator, округленное к целому числу. Таким образом, fmod (6.5, 2.3) возвращает 1.9, который является 6.5-4.6.
Результат имеет тот же самый знак как numerator и имеет величину меньше чем величина denominator.
Если denominator - нуль, fmod сбоит и устанавливает errno как EDOM.
double drem (double numerator, double denominator) (функция)
Функция drem - подобна fmod за исключением того, что она округляет внутреннее частное n к самому близкому целому числу а не к целому числу в сторону нуля. Например, drem (6.5, 2.3) возвращает -0.4, который является 6.5-6.9.
Абсолютное значение результата - меньше или равно половине абсолютного значения denominator. Различие между fmod (numerator, denominator) и drem (numerator, denominator) - всегда либо denominator, либо -denominator, либо нуль.
Если denominator - нуль, drem сбоит и устанавливает errno как EDOM.
14.6 Целочисленное деление
Этот раздел описывает функции для выполнения деления целых чисул. Эти функции избыточны в библиотеке GNU C, с тех пор в GNU C, оператор ` / ' всегда округляется к нулю. Но в других реализациях C, " / " может поступать по-другому с отрицательными аргументами. div и ldiv полезны, потому что они определяют как округляется частное: к нулю. Остаточный член имеет тот же самый знак как числитель.
Эти функции определены, чтобы возвратить результат r такой, что значение r.quot*denominator+r.rem равняется numerator.
Чтобы использовать эти средства, Вы должны включить заглавный файл " stdlib.h " в вашей программе.
div_t (тип данных)
Это - структура, используемая, чтобы содержать результат, возвращенный функцией div. Она имеет следующие элементы:
- Int quot частное от деления.
- Int rem остаточный член от деления.
div_t div (int numerator, int denominator) (функция)
Эта функция вычисляет частное и остаточный член от деления numerator на denominator, возвращая результат в структуре типа div_t.
Если результат не может представляться (напр. деление на нуль), поведение не определено.
Вот пример, хотя и не очень полезный.
div_t result; result = div (20, -6);
Теперь result.quot = -3, а result.rem = 2.
ldiv_t (тип данных)
Это - структура, используемая, чтобы содержать результат, возвращенный функцией ldiv. Она имеет следующие элементы:
long int quot
Частное от деления.
long int rem
Остаточный член от деления. (идентично div _t за исключением того, что компоненты имеют тип long int а не int.)
ldiv_t ldiv (long int numerator, long int denominator) (функция)
Функция ldiv подобна div, за исключением того, что аргументы имеют тип long int, и результат возвращается как структура ldiv типа.
14.7 Синтаксический анализ Чисел
Этот раздел описывает функции для "чтения" целого числа и чисел с плавающей запятой из строки. Может быть более удобно в некоторых случаях использовать sscanf или одну из подобных функций; см. раздел 7.11 [Форматируемый Ввод]. Но часто Вы можете делать программу более надежной, находя лексемы в строке вручную, и преобразуя их в числа один за другим.
Последовательный Синтаксический анализ
Эти функции объявлены в " stdlib.h ".
long int strtol (const char *string, char **tailptr, int base) (функция)
Strtol ("string-to-long") функция преобразовывает начальную часть строки в целое число со знаком, которое возвращено как значение long int.
Если строка является пустой, содержит только пропуск(и), или не содержит начальную подстроку, которая имеет ожидаемый синтаксис для целого числа с заданным base, никакое преобразование не выполняется. В этом случае, strtol возвращает нулевое значение, а значение, сохраненное в *tailptr - значение строки.
Если строка имеет допустимый синтаксис для целого числа, но значения не представимы из-за переполнения, strtol возвращает или LONG_MAX или LONG_MIN (см. Раздел A. 5.2 [Диапазон Типа]), соответствующее знаку значения. Она также устанавливает errno как ERANGE, чтобы указать, что имелось переполнение.
См. пример в конце этого раздела.
unsigned long int strtoul (const char *string, char **tailptr, int base)
Strtoul ("string-to-unsigned-long") функция - подобна strtol за исключением того, что она возвращает значение с типа long unsigned int. Значение, возвращенное в случае переполнения - ULONG_MAX (см. Раздел A. 5.2 [Диапазон Типа]).
long int atol (const char *string) (функция)
Эта функция подобна strtol функции с аргументом base 10, за исключением того, что ей не требуется обнаруживать ошибки переполнения. Atol функция обеспечивается обычно для совместимости с существующим кодом; использование strtol более надежно.
int atoi (const char *string) (функция)
Эта функция - подобна atol, за исключением того, что она возвращает значение int а не long int. Atoi функция также рассматривается устаревшей; используйте strtol.
Вот функция, которая анализирует строку как последовательность целых и возвращает их сумму:
int sum_ints_from_string (char *string) { int sum = 0; while (1) { char *tail; int next; while (isspace (*string)) string++; if (*string == 0) break; errno = 0; next = strtol (string, &tail, 0); if (errno) printf ("Overflow\n"); else sum += next; string = tail; } return sum; }
Синтаксический анализ Float
Эти функции объявлены в " stdlib.h ".
double strtod (const char *string, char **tailptr) (функция)
Strtod ("string-to-double") функция преобразовывает начальную часть строки в число с плавающей запятой, которое возвращается как значение double.
Эта функция пытается разлагать строку следующим образом:
- (Возможно пустая) последовательность символов пропуска. Символы пропуска определяются isspace функцией (см. Раздел 4.1 [Классификация Символов]). Они отброшены.
- Не обязательный "плюс" или "минус" (" + " или " - ").
- Непустая последовательность цифр, необязательно содержащих десятичную точку ".", но это зависит от стандарта (см. Раздел 19.6 [Числовое Форматирование].
- Не обязательная часть экспоненты, состоящая из символа " e " или " E ", знака, и последовательности цифр.
- Если tailptr - не пустой указатель, указатель на этот хвост списка строки сохранен в *tailptr.
Если строка является пустой, содержит только пропуски, или не содержит начальную подстроку, которая имеет ожидаемый синтаксис для числа с плавающей запятой, никакое преобразование не выполняется.
В этом случае, strtod возвращает нуль, а значение, возвращенное в *tailptr - значение строки.
В стандарте отличном от стандарта "C", эта функция может распознавать дополнительный синтаксис.
Если строка имеет допустимый синтаксис для числа с плавающей запятой, но значения, не представимы из-за переполнения, strtod возвращает или положительный или отрицательный HUGE_VAL (см. Главу 13 [Математика]), в зависимости от знака значения. Аналогично, если значение не представимо из-за близости к нулю, strtod возвращает нуль. Она также устанавливает errno как ERANGE, если имелось переполнение или обнуление.
double atof (const char *string) (функция)
Эта функция подобна функции strtod, за исключением того, что ей не требуется обнаруживать ошибки переполнения. Atof обеспечивают обычно для совместимости с существующим кодом; использование strtod более надежно.
15. Поиск и Сортировка
Эта глава описывает функции для поиска и сортировки массивов произвольных объектов. Вы определяете соответствующую функцию сравнения, которую нужно применить как аргумент, наряду с размером объектов в массиве и общим числом элементов.
15.1 Определение Функции Сравнения
Чтобы использовать библиотечные функции сортировки массива, Вы должны описать, как сравнить элементы массива.
Чтобы сделать это, Вы обеспечиваете функцию сравнения, для сравнения двух элементов массива. Библиотека вызовет эту функцию, передавая как указатели на аргументы два элемента массива, которые нужно сравнить. Ваша функция сравнения должна возвратить значение как strcmp (см. Раздел 5.5 [Сравнение СТРОКИ/МАССИВА]): отрицательное, если первый аргумент - "меньше" чем второй, нуль, если они "равны", и положительное если первый аргумент "больше".
Вот пример функции сравнения, которая работает с массивом чисел типа double:
int compare_doubles (const double *a, const double *b) { return (int) (*a - *b); }
Заглавный файл " stdlib.h " определяет имя для типа данных функций сравнения. Этот тип - расширение GNU.
int comparison_fn_t (const void *, const void *);
15.2 Функция Поиска в Массиве
Чтобы искать в сортируемом массиве элемент, соответствующий ключу, используйте bsearch функцию. Прототип для этой функции находится в заглавном файле " stdlib.h ".
void * bsearch (const void *key, const void *array, size_t count, size_t size, comparison_fn_t compare)
Bsearch функция ищет в сортируемом массиве объект, который является эквивалентным key. Массив содержит count элементов, каждый из которых имеет байты размера sise.
Возвращаемое значение - указатель на соответствующий элемент массива, или пустой указатель, если никакое соответствие не найдено. Если массив содержит больше чем один подходящий элемент, неопределено который же возвращается.
Эта функция получила имя из предположения, что она выполнена, используя двоичный алгоритм поиска.
15.3 Функция Сортировки Массива
Для сортировки массива, используюя произвольную функцию сравнения, используйте qsort функцию. Прототип для этой функции находится в " stdlib.h ".
void qsort (void *array, size_t count, size_t size, comparison_fn_t compare)
Qsort функция сортирует заланный массив. Массив содержит count элементов, каждый из которых имеет размер size.
Функция compare используется, чтобы выполнить сравнение на элементах массива. Эта функция вызывается с двумя аргументами указателями и должна возвратить целое число меньше , равное, или больше нуля, если первый аргумент меньше , равен, или больше чем второй аргумент.
Предупреждение: если, два объекта сравниваются как равные, их порядок после сортировки, непредсказуем. То есть сортировка не устойчива. Она может делать различие, когда сравнение рассматривает только часть элементов. А также, два элемента с тем же самым ключом сортировки могут отличиться в других отношениях.
Вот простой пример сортировки массива double значений в числовом порядке используя функцию сравнения, определенную выше (см. Раздел 15.1 [Функции Сравнения]):
{ double *array; int size; . . . qsort(array,size,sizeof(double),compare_doubles); }
Qsort функция получила имя из предположения, что она была первоначально выполнена, используя алгоритм "быстрой сортировки".
15.4 Пример Поиска и Сортировки
Вот пример, показывающий использование qsort и bsearch с массивом структур. Объекты в массиве сортируются, сравнивнением их name полей функцией strcmp.
#include
#include #include struct critter { const char *name; const char *species; }; struct critter muppets[] = { {"Kermit", "frog"}, {"Piggy", "pig"}, {"Gonzo", "whatever"}, {"Fozzie", "bear"}, {"Sam", "eagle"}, {"Robin", "frog"}, {"Animal", "animal"}, {"Camilla", "chicken"}, {"Sweetums", "monster"}, {"Dr. Strangepork", "pig"}, {"Link Hogthrob", "pig"}, {"Zoot", "human"}, {"Dr. Bunsen Honeydew", "human"}, {"Beaker", "human"}, {"Swedish Chef", "human"} }; int count=sizeof(muppets)/sizeof(struct critter); int critter_cmp (const struct critter *c1, const struct critter *c2) { return strcmp (c1->name, c2->name); } void print_critter (const struct critter *c) { printf ("%s, the %s\n", c->name, c->species); } void find_critter (const char *name) { struct critter target, *result; target.name = name; result = bsearch (&target, muppets, count, sizeof (struct critter), critter_cmp); if (result) print_critter (result); else printf ("Couldn't find %s.\n", name); } int main (void) { int i; for (i = 0; i < count; i++) print_critter (&muppets[i]); printf ("\n"); qsort (muppets, count, sizeof (struct critter), critter_cmp); for (i = 0; i < count; i++) print_critter (&muppets[i]); printf ("\n"); find_critter ("Kermit"); find_critter ("Gonzo"); find_critter ("Janice"); return 0; }
Вывод этой программы:
Kermit, the frog Piggy, the pig Gonzo, the whatever Fozzie, the bear Sam, the eagle Robin, the frog Animal, the animal Camilla, the chicken Sweetums, the monster Dr. Strangepork, the pig Link Hogthrob, the pig Zoot, the human Dr. Bunsen Honeydew, the human Beaker, the human Swedish Chef, the human Animal, the animal Beaker, the human Camilla, the chicken Dr. Bunsen Honeydew, the human Dr. Strangepork, the pig Fozzie, the bear Gonzo, the whatever Kermit, the frog Link Hogthrob, the pig Piggy, the pig Robin, the frog Sam, the eagle Swedish Chef, the human Sweetums, the monster Zoot, the human Kermit, the frog Gonzo, the whatever Couldn't find Janice.
16. Сопоставления с образцом
Библиотека GNU C обеспечивает средства сопоставления с образцом для двух видов шаблонов: регулярные выражения и универсальные символы имени файла.
16.1 Универсальное сопоставление
Этот раздел описывает, как шаблон универсальных символов соответствует специфической строке. Результат - ответ да или никакого ответа: строка удовлетворяет шаблону или нет. Символы, описанные здесь объявлены в " fnmatch.h ".
int fnmatch (const char *pattern, const char *string, int flags)
Эта функция проверяет, соответствует ли указанная строка шаблону. Она возвращает 0, если они соответствуют; иначе, она возвращает значение FNM_NOMATCH отличное от нуля.
Flags - комбинация флаговых битов, которые изменяют подробности соответствия. См. ниже список определенных флагов.
В Библиотеке GNU C, fnmatch не может испытывать "ошибку", она всегда возвращает ответ, преуспевает ли соответствие. Однако, другие реализации fnmatch могут иногда сообщать "ошибки", возвращая значения отличные от нуля, которые не равны FNM_NOMATCH.
Вот доступные флаги для аргумента flags:
FNM_FILE_NAME
Если этот флаг установлен, универсальные конструкции символов в шаблоне не могут соответствовать " / " в строке. Таким образом, единственый способ соответствовать " / " явно указать " / " в шаблоне.
FNM_PATHNAME
Это - побочный результат исследования для FNM_FILE_NAME; он исходит ИЗ POSIX.2. Мы не рекомендуем это имя, потому что мы не используем термин "имя пути" для имен файла.
FNM_PERIOD
Обрабатывает "." особенно, если она появляется в начале строки. Если этот флаг установлен, универсальные конструкции символов в шаблоне не могут соответствовать "." (первый символ строки).
Если Вы устанавливаете, и FNM_PERIOD и FNM_FILE_NAME, то "." после "/" трактуется также как к "." в начале строки. (Оболочка использует FNM_PERIOD и FNM_FILE_NAME флаги вместе для соответствия имен файлов.)
FNM_NOESCAPE
Не обрабатывает символ `\' в шаблонах. Обычно, " \ " означает (цитирует) следующий символ непосредственно. Когда цитирование допускается, шаблон " \? " означает строку "? ", потому что вопросительный знак в шаблоне действует подобно обычному символу.
Если Вы используете FNM_NOESCAPE, то " \ " является обычным символом.
FNM_LEADING_DIR
Игнорирует конечную последовательность символов, начинающихся с " / " в строке.
Если этот флаг установлен, и " foo* " и " foobar " как шаблоны, соответствуют строке " foobar/frobozz ".
FNM_CASEFOLD
Игнорирует case при сравнении строки и шаблона.16.2 Globbing
Типичное использование групповых символов - для соответствия файлов в каталоге, и создании списка всех соответствий. Это называется globbing.
Вы могли бы делать это используя fnmatch, читая входы каталога один за другим и проверяя каждый с fnmatch. Но это было бы медлено (и сложно, так как Вы будете должны обработать подкаталоги вручную).
Библиотека обеспечивает функцию glob, чтобы делать это с использованием удобных универсальных символов. Glob и другие символы в этом разделе объявлены в " glob.h ".Вызов glob
Результат globbing - вектор имен файлов. Чтобы возвращать этот вектор, glob использует специальный тип данных, glob _t, который является структурой. Вы передаете glob адрес структуры, и она вносит поля структуры, чтобы сообщить Вам результаты.
glob_t (тип данных)
Этот тип данных содержит указатель на вектор слов. Более точно, он содержит, и адрес вектора слов и размер.
Gl_pathc Число элементов в векторе. Gl_pathv Адрес вектора. Это поле имеет тип char **. Gl_offs Смещение первого реального элемента вектора, от номинального адреса в gl_pathv поле. В отличие от других полей, это -- всегда ввод glob, а не вывод из нее (т. е. вы должны указать его).
Если Вы используете смещение отличное от нуля, то много элементов в начале вектора будут оставлены пустыми. (Функция glob заполняет их пустыми указателями.)
Gl_offs поле значимо только, если Вы используете GLOB_DOOFFS флаг.
Иначе, смещение - всегда нуль независимо от того, что находится в этом поле, и первый реальный элемент расположен в начале вектора.
int glob (const char *pattern, int flags, int (*errfunc) (const char *filename, int error-code), glob_t *vector_ptr)
Эта функция делает globbing, используя указанный шаблон в текущем каталоге. Она помещает результат в недавно размещенном векторе, и сохраняет размер и адрес этого вектора в *vector_ptr. Flags аргумент - комбинация битовых флагов; см. Раздел 16.2.2 [Флаги для Globbing].
Результат globbing - последовательность имен файлов. Glob резервирует строку для каждого возникающего в результате слова, и вектор типа char **, чтобы сохранить адреса этих строк. Последний элемент вектора - пустой указатель. Этот вектор называется вектором слов.
Чтобы возвратить этот вектор, glob сохраняет и адрес и длину (число элементов, не считая завершающий пустой символа) в *vector_ptr.
Обычно, glob сортирует имена файлов в алфавитном порядке перед их возвращением. Вы можете указать флаг GLOB_NOSORT, если Вы хотите получать информацию, с наибольшей скоростью.
Если glob преуспевает, она возвращает 0. Иначе, она возвращает один из этих кодов ошибки:
GLOB_ABORTED Имелась ошибка открытия каталога, и Вы использовали флаг GLOB_ERR, или ваша заданная errfunc возвратила значение отличное от нуля. См. ниже объяснение GLOB_ERR и errfunc.
GLOB_NOMATCH Шаблон не соответствовал ни каким существующим файлам. Если Вы используете GLOB_NOCHECK флаг, то Вы, никогда не получаете этот код ошибки, потому что этот флаг сообщает, чтобы glob симулировал что шаблону соответствует по крайней мере один файл.
GLOB_NOSPACE Было невозможно зарезервировать память, чтобы содержать результат.
В случае ошибки, glob сохраняет информацию в *vector_ptr относительно всей соответствий, которые она уже нашла.Флаги для Glob
Этот раздел описывает флаги, которе Вы можете определять в аргументе flags в glob. Выберите флаги которые Вы хотите, и объедите их оператором OR (| в Си).
GLOB_APPEND
Добавлять слова от этого поиска к вектору слов, произведенных предыдущими обращениями к glob.
Для этого, Вы не должны изменить содержимое структуры вектора слов между обращениями к glob. И, если Вы устанавливаете GLOB_DOOFFS в первом обращении к glob, Вы должны также установить его, когда Вы добавляете.
Обратите внимание, что указатель, сохраненный в gl_pathv может больше не быть допустимым после того, как Вы вызываете glob второй раз, потому что glob может переместить вектор. Так что всегда берите gl_pathv из структуры _t glob после каждого обращения к glob; никогда не сохраните указатель между обращений.
GLOB_DOOFFS
Оставьте пустые места в начале вектора слов. Gl_offs поле говорит сколько мест оставить. Пустые места содержат пустые указатели.
GLOB_ERR
Сразу же сообщает ошибку, если имеется любая трудность. Такие трудности могут включать каталог, в котором Вы не имеете необходимого доступа. Обычно, glob пробует продолжить несмотря на любые ошибки, и читает любые каталоги, какие может.
Вы можете осуществлять управление, определяя функцию обработчика ошибки errfunc, когда Вы вызываете glob. Если errfunc - не пустой указатель, то glob не отказывается сразу же, когда она не может читать каталог; взамен, она вызывает errfunc с двумя аргументами, примерно так:
(*errfunc) (filename, error-code)
Filename - имя каталога, который glob не может открыть, или не может читать, а error-code - значение errno, которое было сообщено glob.
Если функция обработчика ошибки возвращает не нуль, то glob завершается сразу же. Иначе, она продолжается.
GLOB_MARK Если шаблон соответствует имени каталога, конкатенирует " / " к имени каталога при его возвращении.
GLOB_NOCHECK Если шаблон не соответствует ни каким именам файлов, возвращает шаблон непосредственно, как будто это было имя файла. (Обычно, когда шаблон не соответствует чему - нибудь, glob говорит что не имелось никакого соответствия.)
GLOB_NOSOR(***) Не сортирует имена файлов. (Практически, порядок будет зависеть от порядка входов в каталоге.) Единственая причина не сортировать состоит в том, чтобы сохранить время.
GLOB_NOESCAPE Не обрабатывает символ ` \ ' в шаблонах. Обычно, " \ " цитирует следующий символ, выключая специальное значение так, чтобы он соответствовал только непосредственно символу. Когда цитирование допускается, шаблон " \? " соответствует только строке "? ", потому что вопросительный знак в шаблоне действует подобно обычному символу.
Если Вы используете GLOB_NOESCAPE, то " \ " является обычным символом.
Glob делает это, вызывая функцию fnmatch. Она обрабатывает флаг GLOB_NOESCAPE, включая FNM_NOESCAPE флаг в обращениях к fnmatch.16.3 Соответствия Регулярных Выражений
Библиотека GNU C поддерживает два интерфейса для соответствия регулярных выражений. Один - стандартный POSIX.2 интерфейс, а другой - тот, который система GNU использовала много лет.
Оба интерфейса объявлены в заглавном файле " regex.h ". Если Вы определяете _POSIX_C_SOURCE, то будут объявлены только POSIX.2 функции, структуры, и константы.POSIX Регулярные Выражения
Прежде, чем Вы можете фактически использовать регулярное выражение, Вы должны откомпилировать его. Это - не истинная трансляция, это производит специальную структуру данных, а не машинные команды. Но это - подобно обычной трансляции, цель которой дать Вам возможность " выполнить" шаблон быстро. (См. Раздел 16.3.3 [Соответствие POSIX Регулярным Выражениям], для того, как использовать компилируемое регулярное выражение для соответствия.)
Имеется специальный тип данных для компилируемых регулярных выражений:
regex_t (тип данных)
Этот тип содержит компилируемое регулярное выражение. Это - фактически структура. Она имеет только одно поле, которое ваши программы должны рассмотреть: re_nsub . Это поле содержит некоторое число вводных подвыражений регулярного выражения.
Имеются и другие поля, но мы не описываем их здесь, потому что только функции в библиотеке должны использовать их.
После того, как Вы создаете объект regex_t, Вы можете компилировать регулярное выражение в ней, вызывая regcomp.
int regcomp (regex_t *compiled, const char *pattern, int cflags)
Функция regcomp "компилирует" регулярное выражение в структуру данных, которую Вы можете использовать с regexec, чтобы искать соответствующие строки. Компилируемый формат регулярного выражения разработан для эффективного соответствия. Regcomp сохраняет его в *compiled.
Вам нужно только зарезервировать объект типа regex_t и передать адрес regcomp.
Аргумент cflags допускает Вам, определять различные опции, которые управляют синтаксисом и семантикой регулярных выражений.
Если Вы используете флаг REG_NOSUB, то regcomp, опускает из компилируемого регулярного выражения информацию, необходимую для записи соответствий подвыражений. В этом случае, Вы можете также указывать 0 для matchptr и nmatch аргументов, когда Вы вызываете regexec.
Если Вы не используете REG_NOSUB, то компилируемое регулярное выражение имеет запись соответствия подвыражений. Также, regcomp сообщает Вам, сколько подвыражений имеет шаблон, сохраняя число в compiled->re_nsub. Вы можете использовать это значение, чтобы решить, какую длину массива зарезервировать, чтобы содержать информацию относительно соответствий подвыражений.
Regcomp возвращает 0, если она преуспевает в компилировании регулярного выражения; иначе, она возвращает код ошибки отличный от нуля (см. таблицу ниже). Вы можете использовать regerror, чтобы произвести строку сообщения об ошибках для значений отличных от нуля.
Имеются возможные значения отличные от нуля, которые regcomp может возвращать:
REG_BADBR Имеется недопустимая конструкция " \{. . .\} " в регулярном выражении. Допустимая " \{. . .\} " конструкция должна содержать или одиночное число, или два числа в увеличивающемся порядке, отделенные запятой.
REG_BADPAT Имелась синтаксическая ошибка в регулярном выражении.
REG_BADRPT Оператор повторения типа " ? " или " * " оказался, в плохой позиции (без предшествующего подвыражения).
REG_ECOLLATE Регулярное выражение сносится на недопустимый элемент объединения (не определенный в текущем стандарте для строкового объединения). См. Раздел 19.3 [Категории Стандарта].
REG_ECTYPE Регулярное выражение ссылается на недопустимое символьное имя класса.
REG_EESCAPE Регулярное выражение законченно " \ ".
REG_ESUBREG Имелось недопустимое число в " \digit " конструкции.
REG_EBRACK Имелись несбалансированные квадратные скобки в регулярном выражении.
REG_EPAREN Расширенное регулярное выражение имело незакрытые скобки, или базисное регулярное выражение имело несбалансированные "\(" и "\)".
REG_EBRACE Регулярное выражение имело несбалансированные "\{" и "\}".
REG_ERANGE Одна из оконечных точек в выражении диапазона была недопустима.
REG_ESPACE Regcomp не хватает памяти.Флаги для POSIX Регулярных Выражений
Это - битовые флаги, который Вы можете использовать в cflags операнде при компилировании регулярного выражения с regcomp.
REG_EXTENDED
Обрабатывает шаблон как расширенное регулярное выражение, а не как базисное регулярное выражение.
REG_ICASE
Игнорирует case при соответствии символов.
REG_NOSUB
Не сохраняет содержимое matches_ptr массива.
REG_NEWLINE
Обрабатывает символ перевода строки в строке как деление строки на многократные строки, так, чтобы " $ " мог соответствовать перед символом перевода строки, а " ^ " мог соответствовать после. Также, не разрешает "." соответствовать символу перевода строки, и не разрешает " [^. . .] " соответствовать символу перевода строки.
Иначе, символ перевода строки действует подобно любому другому обычному символу.Соответствие Компилируемого POSIX Регулярного Выражения
Если только Вы компилировали регулярное выражение, как описано в Разделе 16.3.1 [Трансляция POSIX Регулярных выражений], Вы можете применять его к строкам используя regexec. Соответствие где-нибудь внутри строки считается как успех, если регулярное выражение не содержит символы " ^ " или " $ ".
int regexec (regex_t *compiled, char *string, size_t nmatch, regmatch_t matchptr [], int eflags) (функция)
Эта функция пробует подобрать соответствие компилируемому регулярному выражению *compiled.
Regexec возвращает 0 если tcnm соответствие выражению; иначе, она возвращает значение отличное от нуля. См. таблицу ниже для того, что означают значения отличные от нуля. Вы можете использовать regerror, чтобы произвести строку сообщения об ошибках для значений отличных от нуля.
Аргумент eflags - слово битовых флагов, которые дают возможность различным опциям.
Если Вы хотите получать информацию относительно части строки которая фактически соответствовала регулярному выражению или подвыражению, используйте аргументы matchptr и nmatch. Иначе, укажите 0 для nmatch, и пустой указатель для matchptr.
Функция regexec принимает следующие флаги в аргументе eflags:
REG_NOTBOL Не расценивает начало заданной строки как начало строки; более вообще, не делает ни каких предположений относительно того, что текст мог бы предшествовать ей.
REG_NOTEOL Не расценивает конец заданной строки как конец строки; более обще, не делает ни каких предположений относительно того, что текст мог бы следовать за ней.
Имеются возможные значения отличные от нуля, которые regexec может возвращать:
- REG_NOMATCH
Шаблон не соответствовал строке. Это в общем не ошибка.
- REG_ESPACE Regexec не хватило памяти.
Результаты Соответствия с Подвыражениями
Когда regexec находит соответствия подвыражениям шаблона, она записывает, которым частям строки они соответствуют. Она возвращает эту информацию, сохраняя смещения в массиве, чьи элементы являются структурами типа regmatch_t. Первый элемент массива (индекс 0) записывает часть строки, которая соответствовала всему регулярному выражению. Каждый другой элемент массива записывает начало и конец части, которая соответствовала одиночному вводному подвыражению.
regmatch_t
Это - тип данных matcharray массива, который Вы передаете к regexec. Он содержит два поля-структуры, следующим образом: Rm_so - Смещение начала подстроки в строке. Добавьте это значение к строке, чтобы получить адрес этой части. Rm_eo - Смещение конца подстроки в строке.
regoff_t
Regoff_t - побочный результат исследования для другого целого типа со знаком. Поля regmatch_t имеют тип regoff_t. Regmatch_t элементы соответствуют подвыражениям позиционно; первый элемент (индекс 1) хранит, где первое согласованное подвыражение, второй элемент записывает второе подвыражение, и так далее. Порядок подвыражений - порядок, в котором они начинаются.
Когда Вы вызываете regexec, Вы определяете длину matchptr массива, с nmatch аргументом.
Это сообщает regexec сколько элементов сохранить. Если фактическое регулярное выражение имеет больше чем nmatch подвыражений, то, Вы не будет получать информацию о смещениях относительно остальной их части.
Еслио Вы не хотите, чтобы regexec возвращал любую информацию относительно подвыражений, Вы можете обеспечить 0 для nmatch, или использовать флаг REG_NOSUB, когда Вы компилируете шаблон с regcomp.Осложнения в Соответствиях Подвыражений
Иногда подвыражение соответствует подстроке без символов. Это случается, когда " f\(o*\) " соответствует строке " fum ". (Оно действительно соответствует только " f ".) В этом случае, оба смещения идентифицируют отметку в строке, где была найдена пустая подстрока. В этом примере, оба смещения 1.
Иногда все регулярное выражение может соответствовать без использования некоторых из подвыражений вообще, например, когда " ba\(na\)* " соответствует строке " ba ", вводное подвыражение не используется. Когда это случается, regexec сохраняет -1 в обоих полях элемента для этого подвыражения.
Иногда при соответствии всего регулярного выражения некоторая подстрока может соответствовать специфическому подвыражению больше чем один раз например, когда " ba\(na\)* " соответствует строка " bananana ", вводное подвыражение соответствует три раза. Когда это случается, regexec обычно сохраняет смещения последней части строки, которая соответствовала подвыражению. В случае " bananana ", эти смещения - 6 и 8.Очистка POSIX Regexp Соответствий
Когда Вы закончили использование компилируемого регулярного выражения, Вы можете освободить память, которую оно использует, вызывая regfree.
void regfree (regex_t *compiled) (функция)
Вызов regfree освобождает всю память, на которую *compiled указывает. Включая различные внутренние поля структуры regex_t, которые не описаны в этом руководстве. Regfree не освобождает объект *compiled непосредственно.
Вы должны всегда освобождать место в структуре regex_t с regfree перед использованием структуры, чтобы компилировать другое регулярное выражение.
Когда regcomp или regexec сообщает об ошибке, Вы можете использовать функцию regerror, преобразовать ее в строку сообщения об ошибках.
size_t regerror (int errcode, regex_t *compiled, char *buffer, size_t length) (функция)
Эта функция производит строку сообщения об ошибках для кода ошибки errcode, и сохраняет строку в length байтах памяти, начинающейся с buffer. Для аргумента compiled, обеспечьте то же самое регулярное выражение, с которой работал regcomp или regexec когда получил ошибку. В качестве альтернативы, Вы можете обеспечивать пустой указатель для compiled; Вы будете все еще получать значимое сообщение об ошибках, но оно может не быть детализировано.
Если сообщение об ошибках не помещается в length байтах (включая пустой символ завершения), то regerror усекает его. Эта строка всегда с нулевым символом в конце даже если она была усечена.
Возвращаемое значение regerror - минимальный length, для сохранения всего сообщения об ошибках. Если он меньше чем length, то сообщение об ошибках не было усечено, и Вы можете использовать его. Иначе, Вы должны вызвать regerror снова с большим buffer.
Вот функция, которая использует regerror, но всегда динамически, резервируя буфер для сообщения об ошибках:
char *get_regerror (int errcode, regex_t *compiled) { size_t length = regerror(errcode,compiled,NULL,0); char *buffer = xmalloc (length); (void) regerror (errcode, compiled, buffer, length); return buffer; }
16.4 Разложение Слов в стиле оболочки
Разложение Слов означает процесс разбивания строки в слова и замену переменных, команд, и универсальных символов, точно так как делает оболочка.
Например, когда Вы пишите " ls -l foo.c ", эта строка разбивается в три отдельных слова " ls ", " -l " и " foo.c ". Это базисная функция разложения слов.
Когда Вы пишите " ls *.c ", это может стать многими словами, потому что слово " *.c " может быть заменено на любое число имен файлов. Это называется разложением универсального символа, и это также часть разложения слова.
Когда Вы используете " ECHO $PATH " чтобы печатать ваш путь, Вы пользуетесь преимуществом замены переменной, которая является также частью разложения слова.
Обычные программы могут выполнять разложение слова точно так же как оболочка, вызывая библиотечную функцию wordexp.Стадии Разложения Слова
Когда разложение слова применяется к последовательности слов, выполняются следующие преобразования в порядке, показанном здесь:
- Разложение Тильды: Замена " ~foo " на имя исходного (home) каталога " foo ".
- Затем, применяются три различных преобразования в том же самом шаге, слева направо:
- Замена переменных: Переменные среды заменяются для ссылок типа " $foo ".
- Замена Команд: Конструкции типа "" cat foo "" и эквивалент " $(cat foo) " заменены на вывод внутренней команды.
- Арифметическое разложение: Конструкции типа " $(($x-1)) " заменены на результат арифметического вычисления.
- Разбивание Поля: разбиение текста в слова.
- Разложение Универсальных символов: замена конструкции типа " *.c " на список " .c " имен файлов. Разложение Универсального символа применяется к всему слову одновременно, и заменяет это слово на 0 или большое количество имен файлов, которые являются самостоятельными словами.
- Удаление Кавычек: стирание кавычек, теперь, когда они сделали их работу, запрещая вышеупомянутые преобразования когда нужно.
Для подробностей этих преобразований, и как написать использующие их конструкции, см. Руководство BUSH (должно появиться).Вызов wordexp
Все функции, константы и типы данных для разложения слова объявлены в заглавном файле " wordexp.h ".
Разложение Слова производит вектор слов (строк). Чтобы возвращать этот вектор, wordexp использует специальный тип данных, wordexp_t, который является структурой. Вы передаете wordexp адрес структуры, и она вносит поля структуры, чтобы сообщить Вам результаты.
wordexp_t
Этот тип данных содержит указатель на вектор слов. Более точно, в нем записаны, и адрес вектора слов и размер. We_wordc - Число элементов в векторе. We_wordv - Адрес вектора. Это поле имеет тип char **. We_offs - Смещение первого реального элемента вектора от номинального адреса в we_wordv поле. В отличие от других полей, это всегда ввод к wordexp, а не вывод из нее.
Если Вы используете смещение отличное от нуля, то многие элементы в начале вектора будут оставлены пустыми. (Wordexp функция заполняет их пустыми указателями.) We_offs поле значимо только, если Вы используете WRDE_DOOFFS флаг. Иначе, смещение - всегда нуль независимо от того, что находится в этом поле, и первый реальный элемент находится в начале вектора.
int wordexp (const char *words, wordexp_t *word-vector-ptr, int flags)
Выполните разложение слова на строке слов, помещая результат в недавно размещенном векторе, и сохраните размер и адрес этого вектора в *word-vector-ptr. Аргумент flags - комбинация битовых флагов; см. Раздел 16.4.3 [Флаги для Wordexp].
Вы не должны использовать любой из символов " | & ; < > " в строке слов, если они не заключены в кавычки; аналогично для символа перевода строки. Если Вы используете эти символы без кавычек, Вы получите WRDE_BADCHAR код ошибки. Не используйте круглые скобки или фигурные скобки, если они заключены в кавычки или часть конструкции разложения слова. Если Вы используете кавычки " ' `, они должены войти попарно.
Результаты разложения слов - последовательность слов. Функция wordexp зарезервирует строку для каждого возникающего в результате слова, и вектор типа char **, чтобы сохранить адреса этих строк. Последний элемент вектора - пустой указатель. Этот вектор называется вектором слов.
Чтобы возвращать этот вектор, wordexp сохраняет, и адрес и длину (число элементов, не считая завершающий пустой символ) в *word vector-ptr.
Если wordexp завершает работу успешно, она возвращает 0. Иначе, она возвращает один из этих кодов ошибки:
- WRDE_BADCHAR
Входные строковые слова содержат незащищенный кавычками недопустимый символ типа " | ".
- WRDE_BADVAL
Входная строка обращается к неопределенной переменной оболочки, и Вы использовали флаг WRDE_UNDEF, чтобы запретить такие ссылки.
- WRDE_CMDSUB
Входная строка использует замену команды, и Вы использовала флаг WRDE_ NOCMD, чтобы запретить замену команд.
- WRDE_NOSPACE
Было невозможно зарезервировать память для результат. В этом случае, wordexp может сохранять часть результатов, столько, сколько она смогла зарезервировать памяти.
- WRDE_SYNTAX
Имелась синтаксическая ошибка во входной строке. Например, несогласованные кавычки - синтаксическая ошибка.
void wordfree (wordexp_t *word-vector-ptr) (функция)
Освободит память, используемую для строки слов и вектора, на который указывает * word-vector-ptr. Она не освобождает структуру *word-vector-ptr непосредственно, а только другие данные, на которые она указывает.Флаги для Разложения Слова
Этот раздел описывает флаги, которые Вы можете определять в аргументе flags wordexp. Выберите флаги, которые Вы хотите, и объединяете их оператором |.
- WRDE_APPEND
Добавляет слова этого разложения к вектору слов, произведенных предыдущими обращениями к wordexp.
Для этого Вы не должны изменять содержимое структуры вектора слов между обращениями к wordexp. И, если Вы устанавливаете WRDE_DOOFFS в первом обращении к wordexp, Вы должны также установить его, когда Вы добавляете.
- WRDE_DOOFFS
Оставляет пустое место в начале вектора слов. We_offs поле говорит, сколько места оставить. Пустое место содержит пустые указатели.
- WRDE_NOCMD
Не делает замену команд; при попытке замены команды, сообщаает об ошибке.
- WRDE_REUSE
Многократно использует вектор слов, сделанный предыдущим обращением к wordexp. Вместо того, чтобы зарезервировать новый вектор слов, это обращение к wordexp использует вектор, который уже существует (увеличивая его в случае необходимости).
Обратите внимание, что вектор может перемещаться в памяти, так что небезопасно хранить старый указатель и использовать его снова после вызова wordexp. Вы должны сохранять we_pathv после каждого обращения.
- WRDE_SHOWERR
Покажет любые сообщения об ошибках.
- WRDE_UNDEF
Если ввод относится к переменной оболочки которая не определена, выдает ошибку.
Пример Wordexp
Вот пример использования wordexp, чтобы рзложить отдельные строки и использования результатов чтобы выполнить команду оболочки. Он также показывает использование WRDE_APPEND, чтобы добавлять разложения и wordfree, чтобы освободить место, размещенное wordexp.
int expand_and_execute(const char*program,const char*options) { wordexp_t result; pid_t pid int status, i; switch (wordexp (program, &result, 0)) { case 0: break; case WRDE_NOSPACE: wordfree (&result); default: return -1; } for (i = 0; args[i]; i++) { if (wordexp (options, &result, WRDE_APPEND)) { wordfree (&result); return -1; } } pid = fork (); if (pid == 0) { execv (result.we_wordv[0], result.we_wordv); exit (EXIT_FAILURE); } else if (pid < 0) status = -1; else if (waitpid (pid, &status, 0) != pid) status = -1; wordfree (&result); return status;
Практически, т. к. wordexp работает, выполняя подоболочку, было бы быстрее сделать это, связывая строки с пробелами между ними и выполняя это как команду оболочки, используюя " sh -c ".17. Дата и время
Эта глава описывает функции для управления датой и временем, включая функции для определения текущего времени и преобразование между различными представлениями времени.
Функции времени относятся к трем категориям:
- Функции для измерения прошедшего времени CPU обсуждены в Разделе 17.1 [Время Процессора].
- Функции календарного времени обсуждены в Разделе 17.2 [Календарное Время].
- Функции для установки будильников и таймеров обсуждены в Разделе 17.3 [Установка Сигнализации].
17.1 Время Процессора
Если вы пробуете оптимизировать вашу программу или измерять эффективность, очень полезно знать, сколько времени процессора или CPU времени она использовала в любой заданной точке. Процессорное время является отличным от фактических часов, потому что оно не включает все потраченное время на ожидание ввода-вывода или когда выполняется некоторый другой процесс. Процессорное время представляется типом данных clock_t, и дано как ряд импульсов времени относительно произвольного базового времени, отмечающего начало одиночного вызова программы.Запрос Основного Времени CPU
Чтобы получить прошедшее CPU время, используемое процессом, Вы можете использовать функцию clock. Это средство объявлено в заглавном файле " time.h ".
Обычно, Вы вызываете функцию clock в начале и конца интервала, который Вы хотите измерить, вычитаете значения, и тогда делите на CLOCKS_PER_SEC (число импульсов времени clock в секунду), примерно так:
#include
clock_t start, end; double elapsed; start = clock(); . . . /* Do the work. */ end = clock(); elapsed=((double)(end-start))/CLOCKS_PER_SEC;
Различные компьютеры и операционные системы сильно отличаются в том, как они следят за процессорным временем. Общее для внутренних часов процессора то, что разрешающая способность где-то между тысячной и милионной долей секунды.
В системе GNU, clock _t эквивалентен long int, а CLOCKS_PER_SEC - целочисленное значение. Но в других системах, и clock _t и тип макрокоманды CLOCKS_PER_SEC может быть или целое число, или с плавающей точкой. Приведением значения времени процессора к double, см. пример выше, удостоверяется, что нужные операции работают правильно и последовательно независимо от того, каково основное представление.
int CLOCKS_PER_SEC
Значение этой макрокоманды - число импульсов времени в секунду, измеряемое функцией clock.
int CLK_TCK
Это - устаревшее имя для CLOCKS_PER_SEC.
clock_t (тип данных)
Это - тип значения, возвращенного функцией clock. Значения типа clock_t измеряются в единицах импульсов сигналов времени clock.
clock_t clock (void) (функция)
Эта функция возвращает прошедшее процессорное время. Базовое время произвольно, но не изменяется внутри одиночного процесса. Если процессорное время не доступно или не может представляться, clock возвращает значение (clock_t) (-1).Детализированный Запрос Времени CPU
Функция times возвращает более детализированную информацию относительно прошедшего процессорного времени в struct tmsobject. Вы должны включить заглавный файл " sys/times.h " чтобы использовать это средство.
struct tms (тип данных)
Структура tms используется, чтобы возвратить информацию относительно времени процесса. Она содержит по крайней мере следующие элементы:
clock_t tms_utime
Это - процессорное время, используемое при выполнении команд вызывающего процесса.
clock_t tms_stime
Это - процессорное время, используемое системой от имени вызываюлщего процесса.
clock_t tms_cutime
Это - сумма значений tms_utime и значений tms_cutime всех завершенных дочерних процессов данного процесса. Другими словами, она представляет общее процессорное время, используемое при выполнении команд всех завершенных дочерних процессов вызывающего процесса.
clock_t tms_cstime
Подобно tms_cutime, но представляет общее процессорное время, используемое системой от имени всех завершенных дочерних процессов.
Все времена даны в импульсах сигналов времени. Они - абсолютные значения; в новом процессе, они - все нуль. См. Раздел 23.4 [Создание Процесса].
clock_t times (struct tms *buffer) (функция)
Функция times сохраняет процессорное время для вызывающего процесса в buffer.
Возвращаемое значение - также как значение clock (): прошедшее реальное время относительно произвольной основы. Основа - константа внутри специфического процесса, и обычно представляет время начиная с запуска системы. Значение (clock_t) (-1) возвращается, чтобы указать отказ.
Примечание Переносимости: функция clock, описанная в Разделе 17.1.1 [Базисное процессорное Время], определена в соответствии c стандартом ANSI C. Функция times - возможность POSIX.1. В системе GNU, значение, возвращенное функцией clock эквивалентно сумме tms_utime и tms_stime полей, возвращенных times.17.2 Календарное Время
Этот раздел описывает средства для слежения за датами и временем согласно Грегорианскому календарю.
Имеются три представления информации даты и времени:
- Календарное время (time_t тип данных) - компактное представление, обычно дает число секунд, истекающих начиная с некоторого основного времени.
- Имеется также представление времени с высоким разрешением (struct timeval тип данных) которое включает доли секунды. Используйте это представление времени вместо обычного календарного времени, когда нужна большая точность.
- Местное время (struct tm тип данных) представляет дату и время как набор компонентов, определяющих год, месяц, и так далее, для специфического часового пояса. Это представление обычно используется вместе с форматированием значений даты и времени.
Простое Календарное Время
Этот раздел описывает time_t тип данных для представления календарного времени, и функции, которые используют объекты календарного времени. Эти средства объявлены в заглавном файле " time.h ".
time_t
Это - тип данных, используемый, чтобы представить календарное время. В библиотеке GNU C и других POSIX-реализациях, time_t эквивалентен long int. Он интерпретируется как абсолютное значение времени и представляет число секунд, истекающих с 00:00:00 1 января, 1970, Координированного Универсального Времени. (Эта дата иногда упоминается как эпоха.)
В других системах, time_t может быть или целым числом или с плавающей запятой.
double difftime (time_t time1, time_t time0) (функция)
Функция difftime возвращает число секунд, между временем time1 и временем time0, как значение типа double.
В системе GNU, Вы можете просто вычитать значения time_t. Но в других системах, time_t тип данных может использовать некоторое другое кодирование, где вычитание не работает непосредственно.
time_t time (time_t *result)
Функция time возвращает текущее время как значение типа time_t. Если аргумент result - не пустой указатель, значение time, также будет сохранено в *result. Если календарный time не доступен, возвращается значение (time_t) (-1).Календарь с высоким разрешением
Тип данных time_t, используемый, чтобы представить календарное вермя имеет разрешающую способность только в одну секунду.
Некоторые приложения нуждаются в большей точности.
Так, библиотека GNU C также содержит функции, которые способны представить календарь с более высокой разрешающей способностью чем одна секунда. Функции и связанные типы данных, описанные в этом разделе объявлены в " sys/time.h ".
struct timeval (тип данных)
Структура struct timeval представляет календарное время. Она имеет следующие элементы:
long int tv_sec
Этот представляет число секунд начиная с зпохи. Это эквивалентно нормальному значению time_t.
long int tv_usec
Это - дробное второе значение, представляемое как число микросекунд.
Некоторые значения struct timeval - используются для временных интервалов. Тогда tv_sec элемент - число секунд в интервале, а tv_usec - число микросекунд.
struct timezone (тип данных)
Структура struct timezone используется, чтобы содержать минимальную информацию относительно зоны местного времени. Она имеет следующие элементы:
int tz_minuteswest
Это - число минут к западу от ГРИНВИЧа.
int tz_dsttime
Если отличен от нуля, сдвинутое время применяется в течение некоторой части года. Struct timezone устаревший тип и не должен использоваться. Вместо этого, используйте средства, описанные в Разделе 17.2.6 [Функции Часового пояса].
Часто необходимо вычесть два значения типа struct timeval. Вот самый лучший способ делать это. Он работает даже на некоторых специфических операционных системах, где tv_sec элемент имеет тип unsigned.
int timeval_subtract (result, x, y) struct timeval *result, *x, *y; { if (x->tv_usec < y->tv_usec) { int nsec = (y->tv_usec-x->tv_usec)/1000000+1; y->tv_usec -= 1000000 * nsec; y->tv_sec += nsec; } if (x->tv_usec - y->tv_usec > 1000000) { int nsec = (y->tv_usec-x->tv_usec)/1000000; y->tv_usec += 1000000 * nsec; y->tv_sec -= nsec; } result->tv_sec = x->tv_sec - y->tv_sec; result->tv_usec = x->tv_usec - y->tv_usec; return x->tv_sec < y->tv_sec; }
int gettimeofday (struct timeval *tp, struct timezone *tzp) (функция)
Функция gettimeofday возвращает текущую дату и время в структуре struct timeval, обозначенной tp. Информация относительно часового пояса возвращается в структуре, указанной в tzp. Если аргумент tzp является пустым указателем, информация часового пояса, игнорируется.
Возвращаемое значение - 0 при успехе и -1 при отказе. Следующее errno условие ошибки определено для этой функции:
- ENOSYS
операционная система не поддерживает получение информации часового пояса, и tzp - не пустой указатель. Операционная система GNU не поддерживает использование struct timezoneto для представления информации часового пояса; это - устаревшая возможность 4.3 BSD. Вместо этого, используйте средства, описанные в Разделе 17.2.6 [Функции Часового пояса].
int settimeofday (const struct timeval *tp, const struct timezone *tzp)
Функция settimeofday устанавливает текущую дату и время согласно аргументам. Что касается gettimeofday, информация часового пояса игнорируется, если tzp - пустой указатель.
Вы должны быть привилегированным пользователем, чтобы использовать settimeofday.
Возвращаемое значение - 0 при успехе и -1 при отказе. Следующие errno условия ошибки определены для этой функции:
- EPERM
Этот процесс не может устанавливать время, потому что он не привилегированный.
- ENOSYS
операционная система не поддерживает установку информации часового пояса, и tzp - не пустой указатель.
int adjtime (const struct timeval *delta, struct timeval *olddelta)
Эта функция ускоряет или замедляет часы системы, чтобы делать постепенные корректировки текущего времени. Она гарантирует, что время, сообщенное часами системы всегда монотонно увеличивается, чего не могло случаться, если Вы просто устанавливаете текущее время.
Аргумент delta определяет относительную корректировку, которая будет сделана относительно текущего времени. Если он отрицателен, часы системы замедляются. Если положителен, часы системы ускоряются.
Если аргумент olddelta - не пустой указатель, функция adjtime, возвращает информацию относительно любой предыдущей корректировки, которая еще не завершилась.
Эта функция обычно используется, чтобы синхронизировать часы компьютеров в местной сети.
Вы должны быть привилегированным пользователем, чтобы использовать ее. Возвращаемое значение - 0 при успехе и -1 при отказе. Следующее errno условие ошибки определено для этой функции:
- EPERM
Вы не имеют привилегий, чтобы установить время.
Примечание Переносимости: функции gettimeofday, settimeofday, и adjtime - из BSD.Разделенное Время
Календарное время представляется как число секунд. Это удобно для вычисления, но не имеет никакого отношения к способу, которым люди обычно представляют даты и время. Нпротив, разделенное время двоичное представление, разделенное на год, месяц, день, и так далее.
Разделенное время всегда зависит от выбора зоны местного времени, и оно также указывает, какой часовой пояс использовался.
Символы в этом разделе объявлены в заглавном файле " time.h ".
struct tm
Это - тип данных, используемый, чтобы представить разделенное время. Структура содержит по крайней мере следующие элементы, которые могут появляться в любом порядке:
int tm_sec
Это - число секунд, обычно в диапазоне от 0 до 59. (Фактическое верхнее ограничение 61, учитывая " прыгающие секунды ".)
int tm_min
Это - число минут, в диапазоне от 0 до 59.
int tm_hour
Это - число часов после полуночи, в диапазоне от 0 до 23.
int tm_mday
Это - день месяца, в диапазоне от 1 до 31.
int tm_mon
Это - число месяцев начиная с января, в диапазоне от 0 до 11.
int tm_year
Это - число лет начиная с 1900.
int tm_wday
Это - число дней начиная с воскресенья, в диапазоне от 0 до 6.
int tm_yday
Это - число дней начиная с 1 января, в диапазоне от 0 до 365.
int tm_isdst
Это - флаг, который указывает действует ли Смещение светового дня (или было, или будет) на описанное время. Значение положительно, если Смещение светового дня включено, нуль, если нет, и отрицательно, если информация не доступна.
long int tm_gmtoff
Это поле описывает часовой пояс, который использовался, чтобы вычислить разделенное значение времени; это значение Вы должны добавить к местному времени в этой зоне, чтобы получить время ПО ГРИНВИЧУ, в секундах. Значение анологично переменной timezone (см. Раздел 17.2.6 [Функции Часового пояса]).
Tm_gmtoff поле расширение библиотеки GNU.
const char *tm_zone
Это поле - трехсимвольное имя для часового пояса, который использовался, чтобы вычислить разделенное время. Это - расширение библиотеки GNU.
struct tm * localtime (const time_t *time) (функция)
Localtime функция преобразовывает календарное время, указываемое TIME в разделенное представление времени, выраженное относительно заданного часового пояса.
Возвращаемое значение - указатель на статическую структуру разделенного времени, которая могла бы быть записана поверх последующими обращениями к любой из функций date и time. (Но никакая другая библиотечная функция не записывает поверх содержимого этого объекта.)
Вызов localtime имеет и другой эффект: она устанавливает переменную tzname с информацией относительно текущего часового пояса. См. Раздел 17.2.6 [Функции Часового пояса].
struct tm * gmtime (const time_t *time) (функция)
Эта функция подобна localtime, за исключением того, что разделенное время выражено как Координированное Универсальное Время (UTC) то есть как Время ПО ГРИНВИЧУ а не относительно зоны местного времени.
Вспомните, что календарное время всегда выражается в координированном универсальном времени.
time_t mktime (struct tm *brokentime) (функция)
Mktime функция используется, чтобы преобразовать структуру разделенного времени в календарное время. Она также "нормализует" содержимое структуры разделенного времени, внося день недели и день года, основываясь на других компонентах даты и времени.
Mktime функция игнорирует заданное содержимое tm_wday и tm_yday элементов структуры разделенного времени. Она использует значения других компонентов, чтобы вычислить календарное время; для этих компонентов допустимо иметь ненормализованные значения вне их нормальных диапазонов. Еще mktime корректирует компоненты структуры brokentime (включая tm_wday и tm_yday).
Если заданное разделенное время не может представляться как календарное время, mktime, возвращает значение (time_t) (-1) и не изменяет содержимое brokentime.
Вызов mktime также устанавливает переменную tzname с информацией относительно текущего часового пояса. См. Раздел 17.2.6 [Функции Часового пояса].Форматирование Даты и времени
Функции, описанные в этом разделе форматирнуют значения времени как строки. Эти функции объявлены в заглавном файле " time.h ".
char * asctime (const struct tm *brokentime) (функция)
Функция asctime преобразовывает значение разделенного времени, на которое указывает brokentime в строку в стандартном формате:
"Tue May 21 13:46:22 1991\n"
Сокращения для дней недели: `Sun', `Mon', `Tue', `Wed', `Thu', `Fri', and `Sat'.
Сокращения для месяцев: `Jan', `Feb', `Mar', `Apr', `May', `Jun', `Jul', `Aug', `Sep', `Oct', `Nov', and `Dec'.
Возвращаемое значение указывает на статически размещенную строку, которая могла бы быть записана поверх последующими обращениями к любой из функций date и time. (Но никакая другая библиотечная функция не записывает поверх содержимого этой строки.)
char * ctime (const time_t *time)
Ctime функция подобна asctime, за исключением того, что значение времени определено в календарном времени (не местное время). Она эквивалентна asctime (localtime (time)) . ctime устанавливает переменную tzname, потому что так делает localtime. См. Раздел 17.2.6 [Функции Часового пояса].
size_t strftime (char *s, size_t size, const char *template, const struct tm *brokentime)
Эта функция подобна sprintf функции (см. Раздел 7.11 [Форматируемый Ввод]), но спецификации преобразования, которые могут появляться в шаблоне формата, специализированы для печати компонентов даты и времени brokentime согласно стандарту, в настоящее время заданному для преобразования времени (см. Главу 19 [Стандарты]).
Обычные символы, появляющиеся в шаблоне копируются в строку вывода s; она может включать многобайтовые символы. Спецификаторы Преобразования представляются символом ` % ', и заменяются в строке вывода следующим образом:
- %a сокращенный день недели согласно текущему стандарту.
- %A полный день недели согласно текущему стандарту.
- %b сокращенный месяц согласно текущему стандарту.
- %B полное название месяца согласно текущему стандарту.
- %c привилегированное представление даты и времени для текущего стандарта.
- %d день месяца как десятичное число (от 01 до 31).
- %H час как десятичное число, используя 24-часовые часы (от 00 до 23).
- %I час как десятичное число, используя 12-часовые часы (от 01 до 12).
- %j день года как десятичное число (от 001 до 366).
- %m месяц как десятичное число (от 01 до 12).
- %M минуты как десятичное число.
- %p Или "am" или "pm", согласно данному значению времени; или соответствующие строки для текущего стандарта.
- %S секунды как десятичное число.
- %U число недель текущего года как десятичное число, начинающееся с первого воскресенья как первый день первой недели.
- %W число недель текущего года как десятичное число, начинающееся с первого понедельника как первый день первой недели.
- %w день недели как десятичное число, воскресенье - 0.
- %x привилегированное представление даты для текущего стандарта, но без времени.
- %X привилегированное представление времени для текущего стандарта, но без даты.
- %y год как десятичное число, но без столетия (от 00 до 99).
- %Y год как десятичное число, включая столетие.
- %Z часовой пояс или имя или сокращение (пусто, если часовой пояс не может быть определен).
- %% литеральный символ ` % '.
Параметр size может использоваться, чтобы определить максимальное число символов, которое будет сохранено в массиве s, включая пустой символ завершения. Если форматируемое время требует больше чем size символов, лишние символы отбрасываются. Возвращаемое значение из strftime - число символов, помещенное в массив s, не включая пустой символ завершения. Если значение равняется размеру, это означает что массив s был слишком мал; Вы должны повторить обращение, обеспечивая больший массив.
Если s - пустой указатель, strftime не делает фактической записи чего-нибудь, но взамен возвращает число символов, которое она написала бы.
Для примера strftime, см. Раздел 17.2.7 [Пример Функции Времени].Определение Часового пояса с TZ
В системе GNU, пользователь может определять часовой пояс посредством TZ переменной среды.
Для уточнения инфрмации относительно того, как устанавливать переменные среды, см. Раздел 22.2 [Переменные среды]. Функции для доступа к часовому поясу объявлены в " time.h ".
Значение TZ переменной может иметь один из трех форматов. Первый формат используется, когда не имеется никакого Смещения светового дня (или в летнее время) в зоне местного времени:
std offset
Std строка определяет имя часового пояса. Эта строка должна состоять из трех или большего количества символов и не должно содержать первым символом двоеточие, и цифры, запятые, плюс или минус внутри.
Смещение определяет значение которое нужно добавить к местному времени, чтобы получить значение Координированного Универсального времени. Она имеет синтаксис подобно [+ | -] hh [: mm [: ss]]. Она положительно, если зона местного времени - к западу от Главного меридиана и отрицательно, если она восточнее. Час должен быть от 0 до 24, а минуты и секунды от 0 до 59.
Например, вот, как мы определили бы Восточное Стандартное Время, но без любых Смещений Светового дня:
EST+5
Второй формат используется, когда имеется Смещение светового дня:
std offset dst [offset],start[/time],end[/time]
Начальные std и offset определяют стандартный часовой пояс, как описано выше. Dst строка и offset определяет имя и смещение для соответствующего Смещения Дня этого часового пояса; если смещение опущено, это значения по умолчанию равно одному часу перед стандартным временем.
Остаточный член от спецификации описывает, когда смещение светового дня действует. Поле start - то, когда смещение светового дня входит в силу, а поле end - то, когда изменение будет сделано обратно к стандартному времени. Следующие форматы распознаваемы для этих полей: Jn определяет Юлианский день, с n между 1 и 365. 29 февраля никогда не рассчитывается, даже в високосные годы. N определяет Юлианский день, с n между 0 и 365. 29 февраля рассчитан в високосные годы. Mm.w.d определяет день d недели w месяца m. день d должен быть между 0 (воскресеньем) и 6. Неделя w должна быть между 1 и 5; неделя 1 - первая неделя, в которой есть день d , а неделя 5 определяет последний d день в месяце. Месяц m должен быть между 1 и 12.
Поля time определяют, когда, по местному времени происходит изменение к другому времени. Значение по умолчанию - 02:00:00.
Например, вот, как можно определить Восточный часовой пояс в Соединенных Штатах, включая соответствующее смещение светового дня и даты применимости. Нормальное смещение ПО ГРИНВИЧУ - 5 часов; так как это - к западу от главного меридиана, знак положителен. Летний период начинается в первое воскресенье апреля в 2:00am, и кончается в последнее воскресенье октября в 2:00am.
EST+5EDT,M4.1.0/M10.5.0
План смещения светового дня в любой юрисдикции не изменяется годами.
Чтобы быть строго правильным, преобразование дат и времени должно быть основано на действующем плане. Однако, система не имеет никаких средств, чтобы допустить Вам определять, как план изменился. Наибольшее что Вы может сделать - определить один специфический план обычно план текущего дня.
Третий формат походит на:
:characters
Каждая операционная система интерпретирует этот формат по разному; в библиотеке GNU C, characters - имя файла, который описывает часовой пояс.
Если переменная среды TZ не имеет значения, операция выбирает часовой пояс по умолчанию. Каждая операционная система имеет собственные правила для выбора заданного по умолчанию часового пояса, так что относительно этого мы можем сказать совсем немного.Функции и Переменные для Часовых поясов
char * tzname [2] (переменная)
Массив tzname содержит две строки, которые являются стандартными трех-символьными именами пары часовых поясов (стандартный и смещения светового дня) которые пользователь выбрал. Tzname [0] имя стандартного часового пояса (например, "EST"), а tzname [1] имя для часового пояса, когда смещение светового дня находится в использовании (например, "EDT"). Они соответствуют к std и dst строкам (соответственно) из TZ переменной среды. Tzname массив инициализируется из переменной среды TZ всякий раз, когда tzset, ctime, strftime, mktime, или localtime вызывается.
void tzset (void)
Tzset функция инициализирует переменную tzname из значения переменной среды TZ. Обычно вашей программе не нужно вызывать эту функцию, потому что она вызывается автоматически, когда Вы используете другие функции преобразования времени, которые зависят от часового пояса.
Следующие переменные определены для совместимости с System V Unix. Эти переменные устанавливаются вызоввом localtime.
long int timezone
Эта переменная содержит различие между временем ПО ГРИНВИЧУ и местным стандартным временем, в секундах. Например, в США в Восточном часовом поясе значение - 5*60*60.
int daylight
Эта переменная имеет значение отличное от нуля, если применяются стандартные американские правила смещения светового дня.Пример Функции Времени
Вот пример программы, показывающий использование некоторых функций местного и календарного времени.
#include
#include #define SIZE 256 int main (void) { char buffer[SIZE]; time_t curtime; struct tm *loctime; curtime = time (NULL); loctime = localtime (&curtime); fputs (asctime (loctime), stdout); strftime (buffer, SIZE, "Today is %A, %B %d.\n", loctime); fputs (buffer, stdout); strftime (buffer, SIZE, "The time is %I:%M %p.\n", loctime); fputs (buffer, stdout); return 0; }
Она производит примерно такой вывод:
Wed Jul 31 13:02:36 1991 Today is Wednesday, July 31. The time is 01:02 PM.
17.3 Установка Сигнализаций
Функции alarm и setitimer обеспечивают механизм прерывания процесса, в некоторое время. Они делают это, устанавливая таймер; когда время таймер истекает, процесс получает сигнал.
Каждый процесс имеет три доступных независимых таймера интервала:
- Таймер в реальном времени, который считает время как часы. Этот таймер посылает сигнал SIGALRM процессу, когда время истекает.
- Виртуальный таймер, который считает процессорное время, используемое процессом. Этот таймер посылает сигнал SIGVTALRM процессу, когда время истекает.
- Таймер профилирования, который считает оба: процессорное время, используемое процессом, и процессорное время, потраченное в системных вызовах от имени процесса. Этот таймер посылает сигнал SIGPROF процессу, когда время истекает.
Вы можете иметь только один таймер каждого вида в любое заданное время. Если Вы устанавливаете таймер, который еще не истек, этот таймер будет сброшен в новое значение.
Вы должны установить обработчик для соответствующего сигнала alarm, используюя signal или sigaction перед обращением к setitimer или alarm. Иначе, необычная цепочка событий может заставлить таймер исчерпать время прежде, чем ваша программа установит обработчик, и в этом случае она будет завершена, так как это - заданное по умолчанию действие для сигналов alarm. См. Главу 21 [Обработка Сигнала].
Функция setitimer - первичный способ для установки будильника. Это средство объявлено в заглавном файле " sys/time.h ". Функция alarm, объявленная в " unistd.h ", обеспечивает несколько более простой интерфейс для установки таймера в реальном времени.
struct itimerval (тип данных)
Эта структура используется, чтобы определить, когда таймер должен истечь. Она содержит следующие элементы:
struct timeval it_interval
Это - интервал между последовательными прерываниями по таймеру. Значение - нуль, если сигнал будет только послан один раз.
struct timeval it_value
Это - интервал до первого прерывания по таймеру. Значение - нуль если, он заблокирован.
Тип данных Struct timeval описан в Разделе 17.2.2 [Календарь с высоким разрешением].
int setitimer (int which, struct itimerval *old, struct itimerval *new)
Функция setitimer устанавливает таймер, заданный как which согласно new. Аргумент which может иметь значение ITIMER_REAL, ITIMER_VIRTUAL, или ITIMER_PROF.
Если old - не пустой указатель, setitimer возвращает информацию относительно любого предыдущего неистекшего таймера того же самого вида в структуре, на которую он указывает.
Возвращаемое значение - 0 при успехе и -1 при отказе. Следующие errno условия ошибки определены для этой функции:
- EINVAL
интервал таймера был слишком большой.
int getitimer (int which, struct itimerval *old)
Getitimer функция сохраняет информацию относительно таймера, заданного which в структуре, указанной в old.
Возвращаемое значение и условия ошибки - такие же как для setitimer.
ITIMER_REAL
Эта константа может использоваться как аргумент which для setitimer и getitimer функций, чтобы определить таймер в реальном времени.
ITIMER_VIRTUAL
Эта константа может использоваться как аргумент which для setitimer и getitimer, чтобы определить виртуальный таймер.
ITIMER_PROF
Эта константа может использоваться как аргумент which для setitimer и getitimer, чтобы определить таймер профилирования.
unsigned int alarm (unsigned int seconds)
Функция alarm устанавливает таймер в реальном времени, с периодом в second секунд. Если Вы хотите отменить любой существующий таймер, Вы может сделать это, вызывая alarm с аргументом 0.
Возвращаемое значение указывает, сколько секунд оставалось прежде, чем предыдущий сигнал был бы послан. Если не было никакого предыдущего сигнала, alarm возвращает нуль.
Функция alarm могла бы быть определена в терминах setitimer примерно так:
unsigned int alarm (unsigned int seconds) { struct itimerval old, new; new.it_interval.tv_usec = 0; new.it_interval.tv_sec = 0; new.it_value.tv_usec = 0; new.it_value.tv_sec = (long int) seconds; if (setitimer (ITIMER_REAL, &new, &old) < 0) return 0; else return old.it_value.tv_sec; }
Имеется пример, показывающий использование функции alarm в Разделе 21.4.1 [Возврат Обработчика].
Если Вы просто хотите, чтобы ваш процесс ждал данное число секунд, Вы должен использовать функцию sleep. См. Раздел 17.4 [Sleep].
Вы не должны рассчитать на сигнал, прибывающий точно, когда таймер истекает. В многопроцессорной среде имеется обычно некоторая задержка.
Примечание Переносимости: setitimer и getitimer - функции UNIX BSD, в то время как функция alarm определена POSIX.1 стандартом. Setitimer более мощная чем alarm, но alarm более широко используется.17.4 Sleep
Sleep дает простой способ заставить программу ждать некоторый период времени. Если ваша программа не использует сигналы (за исключением завершения), то Вы можете расчитывать, что sleep будет ждать заданное количество времени. Иначе, sleep может возвращаться, если прибывает сигнал; если Вы хотите ждать данный период независимо от сигналов, используйте select (см. Раздел 8.6 [Ждущий ввод - вывод] ) и не определяйте ни каких описателей ожидания.
unsigned int sleep (unsigned int seconds)
Функция sleep ждет seconds секунд или пока не получен сигнал.
Если функция sleep возвращает значение по истечении времени, то это значение нуль. Если она возвращается после сигнала, возвращаемое значение - остающееся время ожидания sleep.
Функция sleep объявлена в " unistd.h ".
Вы можете использовать select и делать период ожидания, совершенно точным. (Конечно, загрузка системы может вызывать неизбежные дополнительные задержки, если машина не специализирована одному приложению, не имеется никакого способа, которым Вы можете избежать этого.)17.5 Использование Ресурсов
Функция getrusage и тип данных struct rusage используется для исследования типа использования процесса. Они объявлены в " sys/resource.h ".
int getrusage (int processes, struct rusage *rusage)
Эта функция сообщает общее использование для процессов, заданных в processes, сохраняя информацию в *rusage.
В большинстве систем, processes имеет только два допустимых значения:
RUSAGE_SELF
Только текущий процесс.
RUSAGE_CHILDREN
Все дочерние процессы (прямые и косвенные) которые уже завершились.
В системе GNU, Вы можете также запрашивать относительно специфического дочернего процесса, определяя ID процесса.
Возвращаемое значение getrusage - нуль при успехе, и -1 при отказе.
Аргумент EINVAL processes не допустим.
Еще один способ получения типа использования для специфического дочернего процесса - функцией wait4, которая возвращает общие количества для дочернего процесса при его завершении. См. Раздел 23.8 [BSD Функции Ожидания].
struct rusage
Этот тип данных записывает величину использования различного рода ресурсов. Он имеет следующие элементы (возможны другие):
struct timeval ru_utime
Использованное пользовательское время.
struct timeval ru_stime
Использованное системное время.
long ru_majflt
Число страниц.
long ru_inblock
Число блокировок операций ввода.
long ru_oublock
Число блокировок операций вывода.
long ru_msgsnd
Число посланных сообщений.
long ru_msgrcv
Число полученных сообщений.
long ru_nsignals
Число полученных сигналов.
Дополнительная историческая функция для исследования типов использования, vtimes, обеспечивается но здесь не описана. Она объявлена в " sys/vtimes.h ".17.6 Ограничение Использования Ресурсов
Вы можете определять ограничения использования ресурса для процесса. Когда процесс пробует превышать ограничение, он может терпеть неудачу, в зависимости от ограничения. Каждый процесс первоначально наследует значения ограничений от родителя, но он может впоследствии изменять их.
Символы в этом разделе определены в " sys/resource.h ".
int getrlimit (int resource, struct rlimit *rlp) (функция)
Читает текущее значение и максимальное значение ресурса resource, и сохраняет их в *rlp.
Возвращаемое значение - 0 при успехе и -1 при отказе. Единственое возможное errno условие ошибки - EFAULT.
int setrlimit (int resource, struct rlimit *rlp) (функция)
Сохраняет текущее значение и максимальное значение ресурса в *rlp.
Возвращаемое значение - 0 при успехе и -1 при отказе. Следующее errno условие ошибки возможно:
- EPERM
Вы пробовали изменять максимально допустимое значение ограничения, но Вы не имеете привилегий, чтобы сделать это.
struct rlimit (тип данных)
Эта структура используется с getrlimit, чтобы получить значения ограничений, и с setrlimit, чтобы определить значения ограничений. Она имеет два поля:
Rlim_cur Текущее значение рассматриваемого ограничения.
Rlim_max Максимально допустимое значение рассматриваемого ограничения. Вы не можете устанавливать текущее значение ограничения больше чем этот максимум. Только root может изменять максимально допустимое значение.
В getrlimit, эта структура - вывод; она получает текущие значения. В setrlimit она определяет новые значения.
Вот список ресурсов, для которых Вы можете определять ограничения.
RLIMIT_CPU
Максимальное количество времени центрального процессора которое процесс может использовать. Если он выполняется дольше чем это время, он получает сигнал: SIGXCPU. Значение измеряется в секундах. См. Раздел 21.2.7 [Нестандартные Сигналы].
RLIMIT_FSIZE
Максимальный размер файла котоый процесс может создать. При попытке записать больший файл вызывается сигнал: SIGXFSZ. См. Раздел 21.2.7 [Нестандартные Сигналы].
RLIMIT_DATA
Максимальный размер памяти данных для процесса. Если процесс пробует зарезервировать память больше этого количества, функции резервирования выдает ошибку.
RLIMIT_STACK
Максимальный размер стека для процесса. Если процесс пробует расширять стек больше этого размера, он получает сигнал SIGSEGV. См. Раздел 21.2.1 [Сигналы Ошибки в программе].
RLIMIT_CORE
Максимальный размер core-файла, который этот процесс может создавать. Если процесс завершается и этот максимальный размер не достаточен для core-файла, файл будет усечен.
RLIMIT_RSS
Максимальное количество физической памяти, которое этот процесс может получить. Этот параметр - руководство для планировщика системы и программы распределения памяти; система может давать процессу большее количество памяти, когда имеется излишек.
RLIMIT_OPEN_FILES
Максимальное число файлов, которые процесс может открывать. Если он пробует открывать большее количество файлов, он получает код ошибки EMFILE. См. Раздел 2.2 [Коды Ошибки].
RLIM_NLIMITS
Число различных ограничений ресурсов. Любой допустимый операнд ресурса должен быть меньше чем RLIM_NLIMITS.
int RLIM_INFINITY
Эта константа замещает значение "бесконечности" когда обеспечивается как значение ограничения в setrlimit.
Две исторических функции для установки ограничений ресурса, ulimit и vlimit, не зарегистрированы здесь. Они объявлены в " sys/vlimit.h " и исходят ИЗ BSD.17.7 Приоритет Процесса
Когда отдельные процессы выполняются, их приоритеты определяют то, какую часть ресурсов CPU каждый процесс получает. Этот раздел описывает, как Вы можете читать и устанавливать приоритет процесса. Все эти функции и макрокоманды объявлены в " sys/resource.h ".
Промежуток допустимых значений зависит от операционной системы, но обычно он выполняется от -20 до 20. Меньшее значение приоритета означает что процесс выполняет чаще. Эти константы описывают некоторые значения: PRIO_MIN самое маленькое допустимое значение приоритета. PRIO_MAX самое большое допустимое значение приоритета.
int getpriority (int class, int id) (функция)
Читает приоритет класса процессов, задаваемого class и id (см. ниже).
Возвращаемое значение - значение приоритета при успехе, и -1 при отказе. Следующее errno условие ошибки возможно для этой функции:
- ESRCH
комбинация class и id не соответствует никакому существующему процессу.
- EINVAL
значение class не допустимо.
Когда возвращаемое значение -1, это может указывать отказ, или значение приоритета.
Единственый способ различить состоит в том, чтобы установить errno = 0 перед вызовом getpriority, и тогда использовать errno!= 0 позже как критерий для отказа.
int setpriority (int class, int id, int priority) (функция)
Устанавливает приоритет класса процессов, задаваемого class и id (см. ниже).
Возвращаемое значение - 0 при успехе и -1 при отказе. Следующее errno условие ошибки определено для этой функции:
- ESRCH
комбинация class и id не соответствует никакому существующему процессу.
- EINVAL
значение класса не допустимо.
- EPERM
Вы пробовали устанавливать приоритет процесса некоторого другого пользователя, и Вы не имеете привилегий для этого.
- EACCES
Вы пробовали понизить приоритет процесса, и Вы не имеете привилегий для этого.
Аргументы class и id вместе определяет набор процессов, которыми Вы заинтересованы. Вот возможные значения для class:
PRIO_PROCESS
Читает или устанавливает приоритет одного процесса. id аргумент - ID процесс.
PRIO_PGRP
Читает или устанавливает приоритет одной группы процесса. Аргумент id - ID группы процесса.
PRIO_USER
Читает или устанавливает приоритет процессов одного пользователя. Аргумента id - ID пользователя.
Если id аргумент - 0, то обрабатывается текущий процесс, текущая группа процесса, или текущий пользователь, согласно классу.
int nice (int increment) (функция)
Увеличьте приоритет текущего процесса приращением. Возвращаемое значение не важно.
Вот эквивалентное определение для nice:
int nice (int increment) { int old = getpriority (PRIO_PROCESS, 0); setpriority (PRIO_PROCESS,0,old+increment); }
18. Расширение Символов
Ряд языков использует наборы символов, которые больше чем набор значений типа char.
Японский и Китайский - возможно наиболее близкие примеры.
Библиотека GNU C включает поддержку двух механизмов для работы с расширенными наборами символов: многобайтовые символы и широкие символы. Эта глава описывает, как использовать эти механизмы, и функции для преобразования между ними.
На поведение функций в этой главе воздействует текущий стандарт для символьной классификации LC_CTYPE класса; см. Раздел 19.3 [Категории Стандарта]. Этот стандарт указывает, который многобайтовый код используется, и также управляет значениями и характеристиками расширенных символьных кодов.
18.1 Введение в Расширение Символов
Вы можете представлять расширенные символы одним из двух способов:
Как многобайтовые символы, которые могут быть внедрены в обычной строке, т. е. в массиве объектов char. Их преимущество то, что много программ и операционных систем могут обрабатывать случайные многобайтовые символы, рассеянные среди обычных символов ASCII, без любого изменения.
Как расширенные символы, которые подобны обычным символам за исключением того, что они занимают большое количество битов. Широкий символьный тип данных wchar_t, имеет достаточно места, чтобы содержать расширенные символьные коды также как традиционные коды ASCII.
Преимущество расширенных символов - то, что каждый символ является одиночным объектом данных, точно так же как обычные символы ASCII. Имеются несколько недостатков:
Каждая существующая программа должна быть измененна и перетранслирована, чтобы использовать расширенные символы.
Файлы расширенных символов не могут быть прочитаны программами, которые ожидают обычные символы.
Обычно, Вы используете многобайтовое символьное представление как часть внешнего интерфейса программы, типа чтения или запииси в файлы. Однако, обычно проще выполнить внутренние манипулирования на строках, содержащих расширенные символы, в массивах объектов wchar_t, так как однородное представление делает операции редактирования намного проще. Если Вы используете многобайтовые символы для файлов и расширенные символы для внутренних операций, Вы должен преобразовать их при записи и чтении данных.
Если ваша система поддерживает расширение символов, то она поддерживает их, и как многобайтовые символы и как расширенные символы. Библиотека включает функции, которые Вы можете использовать, чтобы преобразовать между двумя представлениями. Эти функции описаны в этой главе.
18.2 Стандарты и Расширенные Символы
Компьютерная система может поддерживать больше чем один многобайтовый символьный код, и больше чем один расширенный символьный код. Пользователь управляет выбором кодов через текущий стандарт для символьной классификации (см. Главу 19 [Стандарты] ). Каждый стандарт определяет специфический многобайтовый символьный код и специфический расширенный символьный код. Выбор стандарта влияет на поведение функций преобразования в библиотеке.
Некоторые стандарты не поддерживают ни расширенные символы, ни нетривиальные многобайтовые символы. В этих стандартах, библиотечные функции преобразования все еще работают, даже если, что они в основном тривиальны.
Если Вы выбираете нновый стандарт для символьной классификации, внутренний параметр сдвига, поддерживаемый этими функциями может стать спутанным, так что - не стоит изменять стандарт в то время как, Вы находитесь в середине обработки строки.
18.3 Многобайтовые Символы
В обычном коде ASCII, последовательность символов последовательность байтов, и каждый символ - один байт. Это очень просто, но учитывает только 256 различных символов.
В многобайтовом символьном коде, последовательность символов последовательность байтов, но каждый символ может занимать одни или более последовательных байт последовательности.
Имеются много различных способов проектирования многобайтового символьного кода; различные системы используют различные коды. Специфический способ кодирования определяется обозначением базисных последовательностей байтов, которые представляют одиночный символ и какие символы они замещают. Код, который компьютер может фактически использовать, должен иметь конечное число этих базисных последовательностей, и обычно ни одна из них не длиннее чем несколько символов.
Эти последовательности не имеют одинаковую длину. Фактически, многие из их - только один байт. Потому что базисные символы ASCII в промежутке от 0 до 0177 настолько важны, что они замещают себя во всех многобайтовых символьных кодах. То есть байт, чье значение от 0 до 0177 - всегда символ сам по себе. Символы, которые больше чем один байт, должны всегда начинаться с байта в промежутке от 0200 до 0377.
Значение 0 байта может использоваться, чтобы завершить строку, точно как это часто используется в строке символов ASCII.
Определение базисных последовательностей байтов, которые представляют одиночные символы автоматически дают значения более длинным последовательностям байтов, больше чем один символ. Например, если последовательность два байта 0205 049 замещает символ греческой альфы, то 0205 049 065 должна заместить альфу, сопровождаемую " " (код ASCII 065), а 0205 049 0205 049 должна заместить две альфы в строке.
Если любая последовательность байтов может иметь больше чем одно значение как последовательность символов, то многобайтовый код неоднозначен и опасен. Коды, которые системы фактически используют все однозначны.
В большинстве кодов, имеются некоторые последовательности байтов, которые не имеют никакого значения как символ или символы. Они называются недопустимыми.
Самый простой возможный многобайтовый код - тривиальный:
Базисные последовательности состоят из одиночных байтов.
Данный специфический код не использует многобайтовые символы вообще. Он не имеет никаких недопустимых последовательностей. Но он может обрабатывать только 256 различных символов.
Вот другой возможный код, который может обрабатывать 9376 различных символов:
Базисные последовательности состоят из
одиночных байтов со значениями в промежутке от 0 до 0237.
двух-байтовых последовательностей, в которых оба байта имеют значения в промежутке от 0240 до 0377.
Этот код или подобный используется на некоторых системах, чтобы представить Японские символы. Недопустимые последовательности - те, которые состоят из нечетного числа последовательных байтов в промежутке от 0240 до 0377.
Вот другой многобайтовый код, который может обрабатывать больше различных расширенных символов, фактически, почти тридцать миллионов:
Базисные последовательности состоят из
одиночных байтов со значениями в промежутке 0 до 0177.
последовательностей до четырех байтов, в которых первый байт находится в промежутке от 0200 до 0237, а оставшиеся байты находятся в промежутке от 0240 до 0377.
В этом коде, любая последовательность, которая начинается с байта в промежутке от 0240 до 0377, недопустима.
Вот другой вариант, который имеет преимущество: при удалении последнего байта или байтов допустимого символа, никогда не может появиться другой допустимый символ.
Базисные последовательности состоят из
одиночных байтов со значениями в промежутке от 0 до 0177.
двух-байтовых последовательностей, в которых первый байт находится в промежутке от 0200 до 0207, а второй байт находятся в промежутке от 0240 до 0377.
трех-байтовых последовательностей, в которых первый байт находится в промежутке от 0210 до 0217, а другие байты находятся в промежутке от 0240 до 0377.
четырех-байтовых последовательностей, в которых первый байт находится в промежутке от 0220 до 0227, а другие байтаы находятся в промежутке от 0240 до 0377.
Список недопустимых последовательностей для этого кода довольно длинный и не стоит полного просмотра; примеры недопустимых последовательностей включают 0240 и 0220 0300 065.
Число возможных многобайтовых кодов очень велико. Но данная компьютерная система будет поддерживать не больше нескольких различных кодов. (Один из этих кодов может учитывать тысячи различных символов.) Другая компьютерная система может поддерживать полностью отличный код. Библиотечные средства, описанные в этой главе полезны, потому что они описывают подробности многобайтового кода специфической компьютерной системы, хотя ваши программы не должны знать.
Вы можете использовать специальные стандартные макрокоманды, чтобы выяснить максимальное возможное число байтов символа в текущем многобайтовом коде ипользуйте MB_CUR_MAX, а максимум для любого многобайтового кода, обеспечиваемого на вашем компьютере содержится в MB_LEN_MAX.
int MB_LEN_MAX (макрос)
Это - максимальная длина многобайтового символа для любого обеспечиваемого стандарта. Она определена в " limits.h ".
int MB_CUR_MAX (макрос)
Эта макрокоманда отображает (возможно не-константу) положительное целочисленное выражение, которое является максимальным числом байтов в многобайтовом символе в текущем стандарте. Значение никогда не большее чем MB_LEN_MAX.
MB_CUR_MAX определен в " stdlib.h ".
Что случается, если Вы пробуете передавать строку, содержащую многобайтовые символы функции, которая не знает о них? Обычно, такая функция обрабатывает строку как последовательность байтов, и интерпретирует некоторые значения особенно; все другие значения байтов "обычны". Если многобайтовый символ не содержит специальное значение байта, функция должна обработать его, как будто это были отдельные обычные символы.18.4 Введение в Расширенные Символы
Расширенные символы намного проще чем многобайтовые символы. Они - просто символы с больше, чем восемью битами, так, чтобы они имели место для больше, чем 256 различных кодов. Расширенный символьный тип данных wchar_t, имеет достаточно большой диапазон, чтобы содержать расширенные символьные коды также как традиционные коды ASCII.
Преимущество расширенных символов - в том, что каждый символ является одиночным объектом данных, точно так же как обычные символы ASCII. Эти символы также имеют некоторые недостатки:
- Каждая существующая программа должна быть изменена и перетранслирована, чтобы использовать расширенные символы.
- Файлы расширенных символов не могут быть прочитаны программами, которые ожидают обычные символы.
Расширенные символьные значения от 0 до 0177 всегда идентичны кодам символов ASCII. Расширенный нуль часто используется, чтобы завершить строку расширенных символов, точно как, одиночный нулевой байт часто завершает строку обычных символов.
wchar_t (тип данных)
Это - тип " расширенных символов " , целочисленный тип, чей диапазон достаточно велик, чтобы представить все различные значения в любом расширенном наборе символов в обеспечиваемых стандартах. См. Главу 19 [Стандарты], для получения более подробной информации. Этот тип определен в заглавном файле " stddef.h ".
Если ваша система поддерживает расширенные символы, то каждый расширенный символ имеет и расширенный символьный код и соответствующую многобайтовую базисную последовательность.
В этой главе, термин код используется, чтобы обратиться к одиночному расширенному символьному объекту, чтобы подчеркнуть различие от типа данных char.18.5 Преобразование Расширенных Строк
Функция mbstowcs преобразовывает строку многобайтовых символов в массив расширенных символов. Функция wcstombs делает обратный процесс. Эти функции объявлены в заглавном файле " stdlib.h ".
В большинстве программ, эти функции - единственная Ваша потребность в преобразовании между расширенными строками и многобайтовыми символьными строками. Но они имеют ограничения. Если ваши данные не с нулевым символом в конце или - не все в ядре сразу, Вы возможно должны использовать функции преобразования низкого уровня, чтобы преобразовать один символ за раз. См. Раздел 18.7 [Преобразование Одного Символа].
size_t mbstowcs (wchar_t *wstring, const char *string, size_t size)
mbstowcs (" многобайтовая строка в строку расширенных символов ") функция преобразовывает строку с нулевым символом в конце многобайтовых символов в массив расширенных символов, сохраняя не больше чем size расширенных символов в массиве, начинающемся в wstring. Пустой символ завершения рассчитывается в size, так что, если размер меньше, чем фактическое число расширенных символов, следующих из строки, никакой пустой символ завершения не будет сохранен.
Преобразование символов из строки начинается с начальным параметром регистра.
Если недопустимая многобайтовая символьная последовательность найдена, функция возвращает значение -1. Иначе, она возвращает число расширенных символов, сохраненных в массиве wstring. Это число не включает пустой символ завершения, который присутствует, если число меньше, чем size.
Вот пример, показывающий, как преобразовывать строку многобайтовых символов, резервируя достаточное пространство для результата.
wchar_t * mbstowcs_alloc (const char *string) { size_t size = strlen (string) + 1; wchar_t *buf = xmalloc (size * sizeof (wchar_t)); size = mbstowcs (buf, string, size); if (size == (size_t) -1) return NULL; buf = xrealloc (buf, (size + 1) * sizeof (wchar_t)); return buf; }
size_t wcstombs (char *string,const wchar_t wstring,size_t size)
wcstombs преобразует массив расширенных символов с нулевым символом в конце в строку, содержащую многобайтовые символы, сохраняя не больше чем size байт, начиная с string.
Если найден код, который не соответствует допустимому многобайтовому символу, то эта функция возвращает значение -1. Иначе, возвращаемое значение - число байтов, сохраненных в массиве. Это число не включает пустой символ завершения, который присутствует, если число - меньше чем size.18.6 Длина Многобайтового Символа
Этот раздел описывает, как просмотреть строку, содержащую многобайтовые символы, по одному символу. Трудность в том, что нужно знать, сколько байтов каждый символ содержат. Ваша программа может использовать mblen, чтобы узнать это.
int mblen (const char *string, size_t size)
Функция mblen с непустым аргументом string возвращает число байтов, которые составляют многобайтовый символ, начинающийся с string, никогда не исследуя больше size байт. (Идея состоит в том, чтобы обеспечить для size число байтов данных, которые Вы имеете.)
Возвращаемое значение mblen отличает три возможности: первые size байт строки начинаются с допустимого многобайтового символа, они начинаются с недопустимой последовательности байтов или включают только часть символа, или string указывает на пустую строку (пустой символ).
Для допустимого многобайтового символа, mblen возвращает число байтов в этом символе (всегда по крайней мере 1, и никогда не больше чем size). Для недопустимой последовательности байтов, mblen возвращает -1. Для пустой строки, она возвращает 0.
Если многобайтовый символьный код использует символы смены регистра, то mblen, поддерживает и модифицирует параметр регистра. Если Вы вызываете mblen с пустым указателем для строки, она инициализирует параметр регистра к стандартному начальному значению. См. Раздел 18.9 [Параметра Регистра] .
Функция mblen объявлена в " stdlib.h ".18.7 Преобразование Расширенных Символов по Одному
Вы можете преобразовывать многобайтовые символы в расширенные символы по одному mbtowc функцией. Wctomb функция делает обратное. Эти функции объявлены в " stdlib.h ".
int mbtowc (wchar_t *result, const char *string, size_t size)
Mbtowc преобразовывает первый многобайтовый символ в string в соответствующий расширенный символьный код. Она сохраняет результат в *result. Mbtowc никогда не исследует больше чем size байт. (Идея состоит в том, чтобы обеспечить для size число байтов данных, которое Вы имеете.) Mbtowc с непустой строкой Возвращаемое значение mblen отличает три возможности: первые size байт строки начинаются с допустимого многобайтового символа, они начинаются с недопустимой последовательности байтов или включают только часть символа, или string указывает на пустую строку (пустой символ).
Для допустимого многобайтового символа, mbtowc преобразовывает его в расширенный символ, сохраняет его в *result, и возвращает число байтов в том символе (всегда по крайней мере 1, и никогда не болольше чем size).
Для недопустимой последовательности байтов, mbtowc возвращает 1. Для пустой строки, она возвращает 0, также сохраняя 0 в *result.
int wctomb (char *string, wchar_t wchar)
Функция wctomb преобразует расширенный символьный код wchar в соответствующую многобайтовую символьную последовательность, и сохраняет результат в байтах, начиная с string. Wctomb с непустой строкой отличает три возможности для wchar: допустимый расширенный символьный код (тот, который может транслироваться в многобайтовый символ), недопустимый код, и 0.
Если wchar - недопустимый расширенный символьный код, wctomb возвращает -1. Если wchar - 0, она возвращает 0, также сохраняя 0 в *string.
Вызов этой функции с нулевым wchar аргументом, когда строка - не пустой символ, имеет побочный эффект переинициализации сохраненного параметра регистра также как сохранения многобайтового символа 0 и возвращения 0.18.8 Пример Посимвольного Преобразования
Вот пример, который читает многобайтовоый-символьный текст из дескриптора input и записывает соответствующие расширенные символы в описатель output. Мы должны преобразовать символы один за другим в этом примере, потому что mbstowcs неспособна продолжиться после пустого символа, и не может справляться с очевидно недопустимым частичным символом, читая большое количество ввода.
int file_mbstowcs (int input, int output) { char buffer[BUFSIZ + MB_LEN_MAX]; int filled = 0; int eof = 0; while (!eof) { int nread; int nwrite; char *inp = buffer; wchar_t outbuf[BUFSIZ]; wchar_t *outp = outbuf; nread = read (input, buffer + filled, BUFSIZ); if (nread < 0) { perror ("read"); return 0; } if (nread == 0) eof = 1; filled += nread; while (1) { int thislen = mbtowc (outp, inp, filled); if (thislen == -1) break; if (thislen == 0) { thislen = 1; mbtowc (NULL, NULL, 0); } inp += thislen; filled -= thislen; outp++; } nwrite = write (output, outbuf, (outp-outbuf)*sizeof(wchar_t)); if (nwrite < 0) { perror ("write"); return 0; } if ((eof && filled > 0) || filled >= MB_CUR_MAX) { error ("invalid multibyte character"); return 0; } if (filled > 0) memcpy (inp, buffer, filled); } return 1; }
18.9 Многобайтовые Коды, использующие Последовательности Регистров
В некоторых многобайтовых символьных кодах, значение любой специфической последовательности байтов не фиксировано; оно зависит от других последовательностей рассмотренных ранее в той же самой строке. Обычно имеются только несколько последовательностей, которые могут изменять значение других последовательностей; эти немногие называются последовательностями регистров, и мы говорим, что они устанавливают параметр регистра для других последовательностей, которые последуют.
Чтобы проиллюстрировать состояние регистра и последовательности регистров, предположите, что мы устанавливаем, что последовательность 0200 (только один байт) вводит Японский режим, в котором пары байтов в промежутке от 0240 до 0377 являются одиночными символами, в то время как 0201 вводит Латинский-1 режим, в котором одиночные байты в промежутке от 0240 до 0377 являются символами, и интерпретируются согласно набору символов Latin-1 Международной организации по стандартизации. Это - многобайтовый код, который имеет два альтернативных состояния регистра ("Японский режим " и " Латинский-1 режим "), и две последовательности регистров, которые определяют специфические состояния регистра.
Когда используемый многобайтовый символьный код имеет состояния регистра, то mblen, mbtowc и wctomb должны поддерживать и модифицировать текущее состояние регистра, поскольку они просматривают строку. Чтобы делать эту работу правильно, Вы должны следовать этим правилам: * Перед стартом просмотра строки, вызовите функцию с пустым указателем для многобайтового символьного адреса например, mblen (NULL, 0). Это инициализирует состояние регистра к стандартному начальному значению. * Просматривайте строку по одному символу. Не "возвращайтесь" и не перепросмотривайте уже просмотренные символы, и не смешивайте обработку различных строк.
Вот пример использования mblen с соблюдением этих правил:
void scan_string (char *s) { int length = strlen (s); mblen (NULL, 0); while (1) { int thischar = mblen (s, length); if (thischar == 0) break; if (thischar == -1) { error ("invalid multibyte character"); break; } s += thischar; length -= thischar; } }
Функции mblen, mbtowc и wctomb не используются при использовании многобайтового кода, который использует состояние регистра. Однако, никакие другие библиотечные функции не вызывают эти функции, так что Вы не должны волноваться относительно этого.19. Национальные и Международные Стандарты
Различные страны имеют изменяющиеся стандарты. Эти стандарты содержит преобразования от очень простых, типа формата для представления дат и времени, до очень сложных, типа разговорного языка.
Межнационализация программного обеспечения означает способность к адаптированию программирования для соглашений предпочитаемых пользователем. В ANSI C, межнационализация работает посредством стандартов. Каждый стандарт определяет набор соглашений, одно соглашение для каждой цели. Пользователь выбирает набор соглашений, определяя стандарт (через переменные среды).
Все программы наследуют выбранный стандарт как часть их среды.19.1 Какие Эффекты Стандарта Имеет Каждый Стандарт ?
Это определяет соглашения для отдельных целей, включая следующие:
- Какие многобайтовые символьные последовательности являются допустимыми, и как они интерпретируются (см. Главу 18 [Расширенные Символы]).
- Классификация того, какие символы местного набора являются буквенными, верхнего и нижнего регистра (см. Главу 4 [Обработка Символов]).
- Последовательность объединений для местного языка и набора символов (см. Раздел 5.6 [Функции Объединения]).
- Форматирование чисел (см. Раздел 19.6 [Числовое Форматирование]).
- Форматирование дат и времени (см. Раздел 17.2.4 [Форматирование Даты и времени]).
- Какой язык использовать для вывода, включая сообщения об ошибках. (Библиотека C однако не позволяет Вам выполнить это.)
- Какой язык использовать для ответов пользователя на вопросы типа "да" или "нет".
- Какой язык использовать для более сложного ввода пользователя. Некоторые аспекты адаптации к заданному стандарту обрабатываются автоматически библиотечными подпрограммами. Например, все ваши программы должны использовать последовательность объединений выбранного стандарта, т. е. использовать strcoll или strxfrm, чтобы сравнить строки.
Другие аспекты стандартов - вне компетенции библиотеки. Например, библиотека не может автоматически транслировать сообщения вывода вашей программы на другие языки. Единственый способ, которым Вы можете поддерживать вывод на языке пользователя, должен программироваться более или менее вручную. (В конечном счете, мы надеемся обеспечить средства, чтобы делать этот проще.)
Эта глава обсуждает механизм, которым Вы можете изменять текущий стандарт. Эффекты текущего стандарта на специфических библиотечных функциях обсуждены более подробно в описаниях самих функций.19.2 Выбор Стандарта
Самый простой способ для пользователя, чтобы выбрать стандарт состоит в том, чтобы установить переменную среды LANG. Она определяет один стандарт для всех целей. Например, пользователь мог бы определить гипотетический стандарт, именованный " espana castellano " чтобы использовать стандартные соглашения Испании.
Набор обеспечиваемых стандартов зависит от операционной системы, которую Вы используете. Мы не можем делать ни каких обещаний относительно того, что стандарты будут существовать, кроме одного стандартного стандарта, называемого " C " или " POSIX ".
Пользователь также имеет опцию определения различных стандартов для различных целей, выбирая смесь многих стандартов.19.3 Категории Действий, на которые Воздействуют Стандарты
Цели, которые стандарты обслуживают, сгруппированы в категории так, чтобы пользователь или программа мог выбирать стандарт для каждого класса независимо. Вот таблица категорий: каждое имя является и переменной среды, которую пользователь может устанавливать, и именем макрокоманды, которую Вы можете использовать как аргумент setlocale.
LC_COLLATE
Этот класс применяется для объединения строк (функции strcoll и strxfrm); см. Раздел 5.6 [Функции Объединения].
LC_CTYPE
Этот класс применяется для классификации и преобразований символов, и в многобайтовые и в расширенные символы; см. Главу 4 [Обработка Символов] и Главу 18 [Расширенные Символы].
LC_MONETARY
Этот класс применяется к форматированию валютных значений; см. Раздел 19.6 [Числовое форматирование].
LC_NUMERIC
Этот класс применяется к форматированию числовых значений; см. раздел 19.6 [Числовое Форматирование].
LC_TIME
Этот класс применяется для форматирования значений даты и времени; см. Раздел 17.2.4 [Форматирование Даты и времени].
LC_ALL
Это - не переменная среды, это - только макрокоманда, которую Вы можете использовать с setlocale, чтобы установить одиночный стандарт для всех целей.
LANG
Если эта переменная среды определена, значение определяет стандарт, используемый для всех целей за исключением того, как отменено переменными выше.19.4 Как Программы Устанавлиают Стандарт
Программа на Си наследует переменные среды стандарта, когда она начинается. Это случается автоматически. Однако, эти переменные автоматически не управляют стандартом, используемым в соответствии c библиотечными функциями, потому что ANSI C говорит, что все программы начинаются по умолчанию в стандарте " C ". Чтобы использовать стандарты, заданные средой, Вы должны вызвать setlocale. Вызовите ее следующим образом:
setlocale (LC_ALL, "");
чтобы выбрать стандарт, основанный на соответствующих переменных среды.
Вы можете также использовать setlocale, чтобы определить специфический стандарт, для общего использования или для специфического класса.
Символы в этом разделе определены в заглавном файле " locale.h".
char * setlocale (int category, const char *locale)
Функция setlocale устанавливает текущий стандарт для указанного класса.
Если класс - LC_ALL, то она определяет стандарт для всех целей. Другие возможные значения класса определяют индивидуальную цель (см. Раздел 19.3 [Категории Стандарта] ).
Вы можете также использовать эту функцию, чтобы выяснить текущий стандарт, передавая пустой указатель как аргумент стандарта. В этом случае, setlocale возвращает строку, которая является именем стандарта, в настоящее время выбранного для класса class.
Строка, возвращенная setlocale может быть записана поверх последующими обращениями, так что Вы должны делать копию строки (см. Раздел 5.4 [Копирование и Конкатенация]) если Вы хотите сохранять ее после любых дальнейших обращений к setlocale. (Стандартная библиотека, как гарантируют, никогда не вызовет setlocale непосредственно.)
Вы не должны изменять строку, возвращенную setlocale. Это может быть та же самая строка, которая была передана как аргумент в предыдущем обращении к setlocale.
Когда Вы читаете текущий стандарт для класса LC_ALL, значение кодирует всю комбинацию выбранных стандартов для всех категорий. В этом случае, значение не только одиночное имя стандарта. Фактически, мы не делаем ни каких обещаний относительно того, на что это походит. Но если Вы определяете то же самое " имя стандарта" LC_ALL в последующем обращении к setlocale, она восстанавливает ту же самую комбинацию выборов стандарта.
Когда аргумент locale - не пустой указатель, строка, возвращенная setlocale отражает изменяемый стандарт.
Если Вы определяете пустую строку для стандарта, это означает, что нужно читать соответствующую переменную среды и использовать ее значение для установки стандарта указанного класса.
Если Вы определяете недопустимое имя стандарта, setlocale, возвращает пустой указатель и оставляет текущий стандарт неизмененным.
Вот пример, показывающий, как Вы могли бы использовать setlocale, чтобы временно включить к новый стандарт.
#include
#include #include #include void with_other_locale (char *new_locale, void (*subroutine) (int), int argument) { char *old_locale, *saved_locale; old_locale = setlocale (LC_ALL, NULL); saved_locale = strdup (old_locale); if (old_locale == NULL) fatal ("Out of memory"); setlocale (LC_ALL, new_locale); (*subroutine) (argument); setlocale (LC_ALL, saved_locale); free (saved_locale); } Примечание о переносимости: Некоторые системы ANSI C могут определять дополнительные категории стандарта. Для переносимости, запомните, что любой символ, начинающийся с " LC_ " мог бы быть определен в "locale.h".19.5 Стандартные Стандарты
Единственые имена стандартов, которые Вы можете находить во всех операционных системах - это три стандартных: "C" Это - стандартный стандарт Cи. Атрибуты и поведение, которое он обеспечивает определены в стандарте ANSI C. Когда ваша программа начинается, она первоначально использует этот стандарт по умолчанию. " POSIX " Это - стандартный стандарт POSIX. В настоящее время, это - побочный результат исследования для стандартного стандарта Cи. "" Пустое имя говорит о том, что нужно выбрать стандарт, основанный на переменных среды. См. Раздел 19.3 [Категории Стандарта].
Определение и установка стандартов - обязаность вашего администратора системы (или человека, который установил библиотеку GNU C). Некоторые системы могут позволять пользователям создавать стандарты, но мы не обсуждаем это здесь.
Если ваша программа должна использовать кое-что отличное от "C" стандарт, она будет более переносимой, если Вы используете стандарт, который пользователь определяет со средой, а не пробуя определить некоторый ненормативный стандарт явно именем. Помните, что различные машины могут иметь различные наборы устанавливаемых стандартов.19.6 Числовое Форматирование
Когда Вы хотите форматировать число или количество валюты, используя соглашения текущего стандарта, Вы можете использовать функцию localeconv, чтобы получить данные относительно того, как делать это. Функция localeconv объявлена в заглавном файле "locale.h ".
struct lconv * localeconv
Функция localeconv возвращает указатель на структуру, чьи компоненты содержат информацию относительно того, как числовые и валютные значения должны форматироваться в текущем стандарте.
Вы не должны измениять структуру или ее содержимое. Структура может быть записана поверх последующими обращениями к localeconv, или обращениями к setlocale, но никакая другая функция в библиотеке не записывает поверх этого значения.
struct lconv
Это - тип данных значения, возвращенного localeconv.
Если элемент структуры struct lconv имеет тип char, и значение CHAR_MAX, это означает что текущий стандарт не имеет никакого значения для этого параметра.Обобщенные Параметры Числового Форматирования
Это - стандартные элементы struct lconv; хотя могут иметься и другие.
char *decimal_point char *mon_decimal_point
Это - разделители Десятичных точек, используемые в форматировании невалютных и валютных чисел, соответственно. В "C" стандарте, значение decimal_point - ".", а значение mon_decimal_point - "".
char *thousands_sep char *mon_thousands_sep
Это - разделители, используемые, чтобы разграничить группы цифр налево от десятичной точки при форматировании невалютных и валютных чисел, соответственно. В "C" стандарте, оба элемента имеет значение "" (пустая строка).
char *grouping char *mon_grouping
Это - строки, которые определяют, как группировать цифры налево от десятичной точки. Группировка grouping применяется к невалютным количествам, а mon_grouping применяется к валютным числам. Используются или thousands_sep или mon_thousands_sep, чтобы отделить группы цифры.
Каждая строка состоит из десятичных чисел, отделяемых точками с запятой. Последовательные числа (слева направо) дают размеры последовательных групп (справа налево, начиная с десятичной точки). Последнее число в строке используется много раз для всех оставшихся групп.
Если последним целым числом является -1, это означает, что любые остающиеся цифры формируются в одну большую группу без разделителей.
Например, при - "4;3;2", правильная группировка для числа 123456787654321 будет " 12 ", " 34 ", " 56 ", " 78 ", " 765 ", " 4321 ". С разделителем ",", число было бы напечатано как " 12,34,56,78,765,4321 ".
Значение "3" указывает повторение группы из трех цифр, как обычно используется в США.
В стандарте " C ", и grouping и mon_grouping имеют значения "". Это значение не определяет никакой группировки вообще.
char int_frac_digits char frac_digits
Это - целые, указывающие, сколько дробных цифр (направо от десятичной точки) должны отобразиться в валютном значении в международных и местных форматах, соответственно. (Наиболее часто, оба элемента имеют то же самое значение.)
В стандарте " C ", оба этих элемента имеют значение CHAR_MAX, означая "неопределенный".
Мы рекомендуем не печатать никаких дробных цифр. (Этот стандарт также определяет пустую строку для mon_decimal_point, так печать любых дробных цифр только путала бы!)Печать Символа Валюты
Эти элементы структуры struct lconv определяют, как печатать символ, чтобы идентифицировать валютное значение международный аналог " $ ".
Каждая страна имеет два стандартных символа валюты. Местный символ валюты используется обычно внутри страны, в то время как международный символ валюты используется всемирно, чтобы обратиться к валюте этой страны, когда необходимо указать страну недвусмысленно.
Например, многие страны используют доллар в качестве денежной единицы, но для международных валют важно определить, что мы имеем дело с Канадскими долларами, вместо Американских долларов или Австралийских долларов. Но когда контекст известен, не имеется никакой потребности объявлять эти явные долларовые количества в Канадских долларах.
char *currency_symbol
Местный символ валюты для выбранного стандарта.
В стандарте " C ", этот элемент имеет значение "" (пустая строка), означая "неопределенный". Стандарт ANSI не говорит, что делать, когда Вы находите это значение; мы рекомендуем, чтобы Вы просто печатали пустую строку, как Вы печатали бы любую другую строку, найденную в соответствующем элементе.
char *int_curr_symbol
Международный символ валюты для выбранного стандарта.
Значение int_curr_symbol должно обычно состоять из трех символьного сокращения, определенного Международной организацией по стандартизации международного эталона как один из 4217 Кодов для Представления Валюты и Фондов, сопровождаемых разделителем (часто пробел).
В стандарте " C ", этот элемент имеет значение "" (пустая строка), означая "неопределенный". Мы рекомендуем, чтобы Вы просто печатали пустую строку, как Вы печатали бы любую другую строку, найденную в соответствующем элементе.
char p_cs_precedes char n_cs_precedes
Эти элементы равны 1, если currency_symbol строка предшествует значению валютного количества, или 0, если строка следует за значением. P_cs_precedes лемент применяется к положительным значениям (или нулю), а n_cs_precedes элемент применяется к отрицательным значениям.
В стандарте " C ", оба этих элемента имеют значение CHAR_MAX, означая "неопределенный". Стандарт ANSI не говорит, что делать, когда Вы находите это значение, но мы рекомендуем печатать символ валюты перед числом. Это - правильно для большинства стран. Другими словами, обработайте все значения отличные от нуля подобно этим элементам.
Стандарт POSIX говорит, что эти два элемента обращаются к int_curr_symbol также как currency_symbol. Стандарт ANSI C, кажется, подразумевает, что они должны применяться только к currency_symbol_so, int_curr_symbol должен всегда предшествовать количеству.
Мы можем только предполагать, которое из этих соответствует обычному соглашению для печати международных символов валюты. Наше предположение - то, что они должны всегда предшествовать количеству. Если мы выясим точный ответ, мы поместим его здесь.
char p_sep_by_space char n_sep_by_space
Эти элементы равны 1, если между currency_symbol строкой и количеством ставится пробел, или 0, если никакого пробела не ставится. P_sep_by_space элемент применяется к положительным количествам (или нулю), и n_sep_by_space элемент применяется к отрицательным количествам.
В стандарте "C", оба этих элемента имеют значение CHAR_MAX, означая "неопределенный". Стандарт ANSI не говорит, что Вы должны делать, когда Вы находите это значение; мы предлагаем, чтобы Вы обрабатывали это как 1 (печатайте пробел). Другими словами, обрабатывайте все значения отличные от нуля подобно этому элементу.
Эти элементы применяются только к currency_symbol. Когда Вы используете int_curr_symbol, Вы никогда не печатаете дополнительный пробел, потому что int_curr_symbol непосредственно содержит соответствующий разделитель.
Стандарт POSIX говорит, что эти два элемента обращаются к int_curr_symbol также как currency_symbol. Но пример в стандарте ANSI C ясно подразумевает, что они должны применяться только к currency_symbol_that, int_curr_symbol содержит любой соответствующий разделитель, так что Вы никогда не должны печатать дополнительный пробел.
Мы рекомендуем, чтобы Вы игнорировали эти элементы при печати международных символов валюты и не печатали никаких дополнительных пробелов.Печать Значения Количества Денег
Эти элементы структуры struct lconv определяют, как печатать знак в валютном значении.
char *positive_sign char *negative_sign
Это - строки, используемые, чтобы указать положительное (или нуль) и отрицательное (соответственно) валютные количества.
В стандарте "C", оба этих элемента имеет значение "" (пустая строка), означая "неопределенный".
Стандарт ANSI не говорит, что делать, когда Вы находите это значение; мы рекомендуем печатать positive_sign. Для отрицательного значения, печатайте negative_sign, если Вы находите его, если оно и positive_sign пусты, тогда печатайте "-" взамен. (Не указывать знак вообще - кажется довольно неблагоразумным.)
char p_sign_posn char n_sign_posn
Эти элементы имеют значения типа integer и указывают, как позиционировать знак для неотрицательных и отрицательных валютных количеств, соответственно. (Строка, используется знаком определенным в positive_sign или negative_sign.) возможные значения следующие:
0 Символ валюты и количество должны быть окружены круглыми скобками. 1 Печатает строку перед символом валюты и количеством. 2 Печатает строку после символа валюты и количества. 3 Печатает строку сразу перед символом валюты. 4 Печатает строку сразу за символом валюты.
CHAR_MAX "Неопределен". Оба элемента имеют это значение в стандарте " C ". Стандарт ANSI не говорит, что Вы должны делать, когда значение - CHAR_MAX. Мы рекомендуем, чтобы Вы печатали знак после символа валюты.