Next Previous Contents

28. Приложение А: Средства Языка C в Библиотеке

О некоторых средствах, выполненных библиотекой C действительно нужно думать как о части Языка C непосредственно. Эти средства должны быть зарегистрированы в Руководстве Языка C, а не в библиотечном руководстве; но так как мы пока не имеем руководства языка, и документация для этих возможностей пишется, мы издаем его здесь.

28.1 A.1 Явная Проверка Внутренней Непротиворечивости

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

макрокоманда assert, определенная в заглавном файле " assert.h ", обеспечивает удобный способ прервать программу при печати сообщения относительно того, где в программе была обнаружена ошибка.

Если только Вы думаете, что ваша программа отлажена, Вы можете отключать проверки ошибки, выполняемые макрокомандой assert, перетранслируя с определенной макрокомандой NDEBUG. Это означает что Вы, фактически не должны изменить исходный текст программы, чтобы отключить эти проверки.

Но отключение этих проверок непротиворечивости нежелательно, если они не делают программу значительно медленнее. Большое количество проверок ошибок - хорошо независимо от того, кто выполняет программу.

Знающий пользователь хотел бы иметь аварийный отказ программы, явно, чем возврат ерунды без указания, что что-то неправильно.

       void assert (int expression)  (макрос)
Проверяет убеждение программиста, что выражение должно быть отлично от нуля в этом месте программы.

Если NDEBUG не определен, assert проверяет значение выражения. Если оно является ложным (нулем), assert прерывает программу (см. Раздел 22.3.4 [Прерывание выполнения Программы]) после печати сообщения вида:

        `file':linenum: Assertion `expression' failed.
в стандартный поток ошибки stderr (см. Раздел 7.2 [Стандартные Потоки]). Filename и номер строки берутся из макрокоманд препроцессора C __FILE__ и __LINE__.

Если макрокоманда препроцессора NDEBUG определена в отметке, где "assert.h " включен, макрокоманда assert не будет делать абсолютно ничего.

Предупреждение: Даже выражение аргумента не будет оценено, если NDEBUG - определен. Так что никогда не используйте assert с аргументами, которые включают побочные эффекты. Например, assert (++ i> 0); является плохой идеей, потому что i не будет увеличена, если NDEBUG определен.

Примечание Использования: средство assert разработано для обнаружения внутренней несогласованности; оно не подходит для сообщения недопустимого ввода или неподходящего использования пользователем программы.

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

Более того, ваша программа не должна прерываться когда дан недопустимый ввод, а assert сделала бы это выйдя с состоянием отличным от нуля (см. Раздел 22.3.2 [Состояние Выхода]) после печати сообщений об ошибках.

28.2 A.2 Variadic Функции

ANSI C определяет синтаксис для объявления функции, берущей переменное число или тип аргументов. (Такие функции упоминаются как varargs функции или variadic функции.) Однако, язык непосредственно не обеспечивает никакого механизма для таких функций, чтобы обратиться к их не-требуемым аргументам; взамен, Вы используете переменные макрокоманды аргументов, определенные в " stdarg.h ".

Этот раздел описывает, как объявить variadic функции, как написать их, и как вызвать их правильно.

Примечание Совместимости: Намного более старые диалекты C обеспечивают подобный, но несовместимый, механизм для определения функций с переменным числом аргументов, используя " varargs.h ".

A.2.1 Зачем Используются Variadic Функции

Обычные функции C берут фиксированное число аргументов. Когда Вы определяете функцию, Вы определяете тип данных для каждого аргумента. Каждое обращение к функции должно обеспечить ожидаемое число аргументов, с типами, которые могут быть преобразованы в заданные. Таким образом, если функция " foo " объявлена: int foo (int, char*); то Вы должны вызвать ее с двумя аргументами: числом и строковым указателем.

Но некоторые функции выполняют операции, которые могут принимать неограниченное число аргументов.

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

Библиотечная функция printf (см. Раздел 7.9 [Форматируемый Вывод]) - пример другого класса функции, где переменные аргументы полезны. Эта функция печатает аргументы (которые могут изменяться в типе также как в числе) при контроле над строкой шаблона формата.

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

Некоторые функции типа open берут фиксированный набор аргументов, но иногда игнорируют несколько последних. Строгая приверженность ANSI C требует, чтобы эти функции были определены как variadic; практически, однако, компилятор GNU C и большинство других компиляторов C допускает Вам определять такую функцию, чтобы брать фиксированный набор аргументов больше чем она может когда-либо использовать и тогда только объявлять функцию как variadic (или не объявлять аргументы вообще!).

A.2.2 Как Variadic Функции определяются и Используются

Определение и использование variadic функций включает три шага:

A.2.2.1 Синтаксис для Переменных Аргументов

Функция, которая принимает переменное число аргументов, должна быть объявлена с прототипом, который говорит это. Вы записываете фиксированные аргументы как обычные, и тогда указываете ". . ." чтобы указать возможность дополнительных аргументов. Синтаксис ANSI C требует по крайней мере одного фиксированного аргумента перед ". . .". Например,

                int
                func (const char *a, int b, . . .)
                {
                        . . .
                }
выделяет определение функции func, которая возвращает int и берет два требуемых аргумента, const char * и int. Они сопровождаются любым числом анонимных аргументов.

A.2.2.2 Получение Значения Аргумента

Обычные фиксированные аргументы имеют индивидуальные имена, и Вы можете использовать эти имена, чтобы обратиться к их значениям. Но необязательные аргументы не имеют никаких имен коме ". . . ". Как Вы может обращаться к ним ?

Единственый способ обращаться к ним - последовательно, в порядке, в котором они написаны, и Вы должны использовать специальные макрокоманды из " stdarg.h " в следующем процессе:

  1. Вы инициализируете переменную указателя аргумента типа va_list, используя va_start. Указатель аргумента, после инициализации, указывает на первый необязательный аргумент.
  2. Вы обращаетесь к необязательным аргументам последовательными обращениями к va_arg. Первое обращение к va_arg дает Вам, первый необязательный аргумент, следующее обращение дает Вам второй, и так далее.
  3. Вы указываете, что Вы закончили с переменной указателя аргумента, вызывая va_end.
См. Раздел A. 2.2.5 [Макросы Аргумента], для полных определений va_start, va_arg и va_end.

Шаги 1 и 3 должны выполниться в функции, которая принимает необязательные аргументы. Однако, Вы можете передавать va_list переменную как аргумент другой функции и выполнять весь или часть шага 2 там.

Вы можете выполнять всю последовательность из трех шагов несколько раз внутри одного вызова функции. Если Вы хотите игнорировать необязательные аргументы, Вы можете не делать этого.

Вы можете иметь больше чем одну переменную указателя аргумента, если Вы находите приятным. Вы можете инициализировать каждую переменную с va_start, когда Вы пожелаете, и т. д.

A.2.2.3 Сколько Аргументов Обеспечивается

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

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

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

Требуемый аргумент может использоваться как шаблон, чтобы определить и число и типы необязательных аргументов. Аргумент строки формата printf - один пример этого (см. Раздел 7.9.7 [Функции Форматированного Вывода]).

Другая возможность состоит в том, чтобы передать значение " end marker " как последний необязательный аргумент. Например, для функции, которая манипулирует, произвольным числом аргументов указателей, пустой указатель мог бы указывать конец списка параметров. (Она принимает, что пустой указатель иначе не значим для функции.) execl функция работает только этим способом; см. Раздел 23.5 [Выполнение Файла].

A.2.2.4 Вызов Variadic Функции

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

В принципе, функции, которые определены, чтобы быть variadic, должны также быть объявлены, чтобы быть variadic использованием прототипа функции всякий раз, когда Вы вызываете их. (См. Раздел A. 2.2.1 [Variadic Прототипы], для того какэто сделать.) Это - потому что некоторые компиляторы C используют различное соглашение о вызовах, чтобы передать тот же самый набор значений аргумента к функции в зависимости от того, берет ли та функция переменные аргументы или фиксированне аргументы.

Но имеются несколько функций, которые чрезвычайно удобно не объявлять как variadic, например open и printf.

Так как прототип не определяет типы для необязательных аргументов, в обращении к variadic функции, заданные по умолчанию поддержки аргумента выполняются на необязательных значениях аргумента. Это означает объекты типа char или short int (или signed, или нет) преобразуются или в int или в unsigned int, соответственно; а объекты float типа - в double тип. Так, если вызывающий оператор передает char как необязательный аргумент, получится int, и функция должна получить его с va_arg (ap, int).

Преобразование требуемых аргументов управляется прототипом функции обычным способом: выражение аргумента преобразовано в объявленный тип аргумента.

A.2.2.5 Макросы Доступа к Аргументу

Имеются описания макрокоманд, используемых, чтобы отыскать переменные аргументы. Эти макрокоманды определены в заглавном файле " stdarg.h ".

       va_list  (тип данных)
Тип va_list используется для переменной указателя аргумента.
       void va_start (va_list ap, last_required)  (макрос)
Эта макрокоманда инициализирует переменную указателя аргумента ap, чтобы указать на первый из необязательных аргументов текущей функции; last_required должен быть последний требуемый аргумент функции.

См. Раздел A.2.3.1 [Старый Varargs], для альтернативного определения va_start в заглавном файле " varargs.h ".

       type va_arg (va_list ap, type)  (макрос)
Va_arg макрокоманда возвращает значение следующего необязательного аргумента, и изменяет значение ap, чтобы указsdать на последующий аргумент. Таким образом, последовательные использования va_arg возвращают последовательные необязательные аргументы.

Тип значения, возвращенного va_arg - type как определено в обращении. type должен быть само-поддерживающийся тип (не char или short int или float) который соответствует типу фактического аргумента.

       void va_end (va_list ap)  (макрос)
Он заканчивает использование ap. После обращения va_end, дальнейшие va_arg обращения с тем же самым ap не могут работать. Вы должны вызвать va_end перед возвращением из функции, в которой va_start вызывался с тем же самым аргументом ap.

В библиотеке GNU C, va_end не делает ничего, и Вы не нуждаетесь в его использовании, кроме причин переносимости.

A.2.3 Пример Variadic Функции

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

                #include <stdarg.h>
                #include <stdio.h>
                int
                add_em_up (int count,...)
                {
                        va_list ap;
                        int i, sum;
                        va_start (ap, count);
                        sum = 0;
                        for (i = 0; i < count; i++)
                                sum += va_arg (ap, int); 
                        va_end (ap); 
                        return sum;
                }
                int
                main (void)
                {
                        printf ("%d\n", add_em_up (3, 5, 5, 6));
                        printf ("%d\n", add_em_up (10, 1, 2, 3, 4, 5,                   
                        6, 7, 8, 9, 10));
                        return 0;
                }

A.2.3.1 Variadic Функции Старого стиля

Раньше ANSI C программисты использовали немного отличное средство для написания variadic функции. Компилятор GNU C все еще поддерживает его; в настоящее время оно более переносимое чем средство ANSI C, так как поддержка для ANSI C все еще не универсальна. Заглавный файл, который определяет традиционное variadic средство называется " varargs.h ".

Использование " varargs.h " почти такое же как использование " stdarg.h ". Не имеется никакого различия в том, как Вы вызываете variadic функцию; См.Раздел A. 2.2.4 [Вызов Variadics]. Единственое различие находится в том, как Вы определяете их. Прежде всего Вы должны использовать синтаксис не-прототипа старого стиля, примерно так:

                tree
                build (va_alist)
                                va_dcl
                {
Во-вторых, Вы должны дать va_start только один аргумент, примерно так:
                        va_list p;
                        va_start (p);
Вот специальные макрокоманды, используемые для определения variadic функций старого стиля:
       va_alist  (макрос)
Эта макрокоманда замещает список имени аргумента, требуемый в variadic функции.
       va_dcl  (макрос)
Эта макрокоманда объявляет неявный аргумент или аргументы для variadic функции.
       void va_start (va_list ap)  (макрос)
Эта макрокоманда, как определено в " varargs.h ", инициализирует ap переменную указателя аргумента, чтобы указывать на первый аргумент текущей функции.

Другие макрокоманды аргумента, va_arg и va_end, те же самые в " varargs.h " как и в " stdarg.h "; см. Раздел A. 2.2.5 [Макросы Аргумента].

Это не работает, чтобы включить, и " varargs.h " и " stdarg.h " в той же самой трансляции; они определяют va_start противоречии способами.

28.3 A.3 Константа - Нулевой Указатель

Пустой указатель, как гарантируют, не укажет на любой реальный объект. Вы можете назначать ее для любой переменной указателя, так как она имеет тип void *. Обычный способ записи пустого указателя - NULL.

       void * NULL  (макрос)
Это - пустой указатель.

Вы можете также использовать 0 или (void *) 0 как нулевые указатели, но использование NULL более чистое, потому что это делает цель константы более очевидной.

Если Вы используете NULL как аргумент функции, то для полной переносимости, Вы должен удостовериться, что функция имеет объявление прототипа. Иначе, если целевая машина имеет два различных представления указателя, компилятор не будет знать которое представление использовать для этого аргумента. Вы можете избежать этой проблемы, явно приводя константу к соответствующему типу указателя, но мы рекомендуем добавить прототип для функции, которую Вы вызываете.

28.4 A.4 Важные Типы Данных

Результат вычитания двух указателей на C - всегда целое число,но точный тип данных изменяется от компилятора к компилятору. Аналогично, тип данных результата sizeof также изменяется между компиляторами. ANSI определяет стандартные побочные результаты исследования для этих двух типов, так что Вы можете обратиться к ним в переносимом режиме. Они определены в заглавном файле " stddef.h ".

       ptrdiff_t  (тип данных)
Это - целочисленный со знаком тип результата вычитания двух указателей. Например, с объявлением char *p1*, p2;, выражение p2 - p1 имеет тип ptrdiff_t.

Это будет возможно один из стандартных целочисленных со знаком типов (short int, int или long int), но мог бы быть нестандартный тип, который существует только для этой цели.

       size_t  (тип данных)
Это - целочисленный беззнаковый тип, используемый, чтобы представить размеры объектов. Результат оператора sizeof имеет этот тип, и функции типа malloc (см. Раздел 3.3 [Беспрепятственное Резервирование]) и memcpy (см. Раздел 5.4 [Копирование и конкатенация]) принимают аргументы этого типа, чтобы определить объектные размеры.

Примечание Использования: size_t - привилегированный способ объявить любые аргументы или переменные, которые содержат размер объекта.

В системе GNU size_t эквивалентен или unsigned int или unsigned long int. Эти типы имеют идентичные свойства в системе GNU, и для большинства целей, Вы можете использовать их неизменяя. Однако, они различны как типы данных, что дает различие в некоторых контекстах.

Примечание Совместимости: Реализации C перед появлением ANSI C вообще использовали unsigned int для представления объектных размеров и int для результатов вычитания указателей. Они не обязательно определяли или size_t или ptrdiff_t. Системы UNIX определяли size_t, в " sys/types.h ", но определение было обычно знаковым типом.

28.5 A.5 Размеры Типов Данных

Большинство времени, если Вы выбираете соответствующий тип данных для каждого объекта в вашей программе, Вы не должны иметь отношение к тому, как они представляются или сколько битов они используют. Когда Вы нуждаетесь в такой информации, Язык C непосредственно не обеспечивает способ получить это. Заглавные файлы " limits.h " и " float .h " содержит макрокоманды, которые дают Вам эту информацию.

A.5.1 Вычисление Ширины Целого

Наиболее общая причина, по которой программа должна знать, сколько битов находятся в целочисленном типе - для использования массива long int как битового вектора. Вы можете обращаться к биту с индексом n как vector[n / LONGBITS] & (1 << (n % LONGBITS)), если Вы определяете LONGBITS как число битов в long int.

Не имеется никакого оператора в Языке C, который может давать Вам число битов в целочисленном типе данных. Но Вы можете вычислять его из макрокоманды CHAR_BIT, определенный в заглавном файле " limits.h ".

CHAR_BIT Это - число битов в char; восемь, на большинстве систем. Значение имеет тип int.

Вы можете вычислять число битов в любом типе данных примерно так:

                        sizeof (type) * CHAR_BIT

A.5.2 Промежуток Целого Типа

Предположите, что Вы должны сохранить целочисленное значение, которое может быть в промежутке от нуля до одного миллиона. Который тип является самым маленьким типом, который Вы можете использовать? Не имеется никакого общего правила; это зависит от компилятора C и целевой машины. Вы можете использовать " MIN " и " МАX " макрокоманды в " limits.h " чтобы определить, который тип будет работать.

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

Значения этих макрокоманд - все целочисленные постоянные выражения. " MAX " и " MIN " макрокоманды для char и short int имеют значения типа int. " MAX " и " MIN " макрокоманды для других типов имеет значения того же самого типа, описанного макрокомандой таким образом, ULONG_MAX имеет unsigned long int тип.

       SCHAR_MIN
Это - минимальное значение, которое может представляться signed char.
       SCHAR_MAX
       UCHAR_MAX
Это - максимальные значения, которые могут представлять signed char и char без знака, соответственно.

       CHAR_MIN
Это - минимальное значение, которое может представлять char. Оно равно SCHAR_MIN, если char - со знаком, или нуль иначе.
       CHAR_MAX
Это - максимальное значение, которое может представлять char. Оно равно SCHAR_MAX, если char - со знаком, или UCHAR_MAX иначе.
       SHRT_MIN
Это - минимальное значение, которое может представлять signed short int. На большинстве машин, на которых библиотека GNU C выполняется, короткие целые - 16 битовые.
       SHRT_MAX
       USHRT_MAX
Это - максимум, который может представляться signed short int и unsigned short int, соответственно.
       INT_MIN
Это - минимальное значение, которое может представляться signed int. На большинстве машин, на которых система GNU C выполняется, int - 32 битовый.
       INT_MAX
       UINT_MAX
Это - максимум, который может представляться, соответственно, signed int типом и unsigned int типом.
       LONG_MIN
Это - минимальное значение, которое может представляться signed long int. На большинстве машин, на которых система GNU C выполняется, длинные целые числа - 32 битовые, того же самого размера как int.
       LONG_MAX
       ULONG_MAX
Это - максимум, который может представляться signed long int и unsigned long int, соответственно.
       LONG_LONG_MIN
Это - минимальное значение, которое может представляться signed long long int. На большинстве машин, на которых система GNU C выполняется, длинные длинные целые числа - 64 битовые.
       LONG_LONG_MAX
       ULONG_LONG_MAX
Это - максимум, который может представляться signed long long int и unsigned long long int, соответственно.

       WCHAR_MAX
Это - максимальное значение, которое может представляться wchar_t. См. Раздел 18.4 [Введение в Расширенные Символы].

Заглавный файл " limits.h " также определяет некоторые дополнительные константы, которые операционная система и файловая система ограничивает. Эти константы описаны в Главе 27 [Конфигурация Системы].

A.5.3 Плавающий Тип

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

Заглавный файл " float .h " описывает формат, используемый вашей машиной.

A.5.3.1 Концепции Представления Чисел С Плавающей Запятой

Этот раздел представляет терминологию для описания представлений с плавающей запятой.

Вы возможно уже знакомы с большинством этих понятий в терминах научного или экспоненциального представления чисел для чисел с плавающей запятой. Например, число 123456.0 могло бы быть выражено в экспоненциальном представлении как 1.23456e + 05, укорченная запись, указывающая, что мантисса 1.23456 умножена на основание 10 в степени 5.

Более формально, внутреннее представление числа са плавающей запятой может характеризоваться в терминах следующих параметров:

Снова, библиотека GNU не обеспечивает никаких средств для работы с такими аспектами представления низкого уровня.

Мантисса числа с плавающей запятой фактически представляет неявную дробь, чей знаменатель является основой в степени точности. Так как самая большая представимая мантисса на один меньше чем этот знаменатель, значение дроби - всегда строго меньше чем 1. Математическое значение числа с плавающей запятой - произведние этой дроби, знака, и основы в стпени экспоненты.

Мы говорим, что число с плавающей запятой нормализовано, если дробь ­ по крайней мере 1/b, где b - основа. Другими словами, мантисса была слишком большая для представления, если она была бы умножена на основу. Не­ нормализованные числа иногда называются нестандартными; они содержат меньшее количество точности чем представление, обычно может содержать.

Если число не нормализовано, то Вы может вычитать 1 из экспоненты при умножении мантиссы на основу, и получать другое число с плавающей запятой с тем же самым значением. Нормализация состоит из выполнения этого неоднократно, пока число не нормализовано. Два различных нормализованных числа с плавающей запятой не могут быть равны в значении.

A.5.3.2 Параметры с плвающей точкой

К этим макроопределениям можно обращаться, включая заглавный файл " кfloat.h " в вашей программе.

Имена макрокоманд, начинающиеся с " FLT_ " относятся к float типу, в то время как имена, начинающиеся с " DBL_ " обращаются к double типу, а имена, начинающиеся " LDBL_ " относит к long double типу. (В настоящее время GCC не поддерживает long double как отдельный тип данных, так что значения для "LDBL_ " константы равны соответствующим константам для double типа.)

Из этих макрокоманд, только FLT_RADIX, как гарантируют, будет постоянным выражением. Другие макрокоманды, перечисленные здесь не могут надежно использоваться в местах, которые требуют постоянных выражений, типа " #if " директив предварительной обработки или в размерах статических массивов.

Хотя стандарт ANSI C определяет минимальные и максимальные значения для большинства этих параметров, реализация GNU C использует любые значения, описывающие представление с плавающей запятой целевой машины. Так в принципе GNU C фактически удовлетворяет требования ANSI C только, если целевая машина подходящая. Практически, все машины, в настоящее время обеспечиваемые, подходящие.

       FLT_ROUNDS
Это значение характеризует режим округления для сложения с плавающей запятой. Следующие значения указывают режимы округления:
       -1        Режим - неопределенный
       0         Округление к нулю.
       1         Округление к самому близкому числу.
       2         Округление к положительной бесконечности.
       3         Округление к отрицательной бесконечности.
Любое другое значение представляет машинно-зависимый нестандартный режим округления.

На большинстве машин, значение 1, в соответствии с стандартом ИИЭРа для чисел с плавающей запятой.

Вот таблица, показывающая, как некоторые значения округляются для каждого возможного значения FLT_ROUNDS.

                     0         1              2             3
        1.00000003   1.0       1.0            1.00000012    1.0       
        1.00000007   1.0       1.00000012     1.00000012    1.0       
       -1.00000003  -1.0      -1.0           -1.0          -1.00000012
       -1.00000007  -1.0      -1.00000012    -1.0          -1.00000012
       FLT_RADIX
Это - значение основы или основания системы счисления. Оно, как гарантируют, будет постоянным выражением, в отличие от других макрокоманд, описанных в этом разделе. Значение - 2 на всех машинах, о которых мы знаем за исключением IBM 360 и производных.
       FLT_MANT_DIG
Это - число (FLT_RADIX-ичных) цифр в мантиссе с плавающей запятой для типа данных float. Следующее выражение производит 1.0 (даже если математически этого не должно быть) из-за ограниченного числа цифр мантиссы:
                float radix = FLT_RADIX;
                1.0f + 1.0f / radix / radix / . . . / radix
где основание системы счисления появляется FLT_MANT_DIG раз.
       DBL_MANT_DIG
       LDBL_MANT_DIG
Это - число (FLT_RADIX-ичных) цифр в мантиссе с плавающей запятой для double и long double, соответственно.
       FLT_DIG
Это - число десятичных цифр точности для типа данных float. Технически, если p и b - точность и основа (соответственно) для представления, то десятичная точность q - максимальное число десятичных цифр таких, что любое число с плавающей запятой с q-основанием из 10 цифр может быть округлено к числу с плавающей запятой с p-основанием из b цифр и обратно снова, без изменения q десятичных цифр.

Значение этой макрокоманды, как предполагается, является по крайней мере 6, для удовлетворения ANSI C.

       DBL_DIG
       LDBL_DIG
Они подобны FLT_DIG, но для double и long double, соответственно. Значения этих макрокоманд, как предполагается, являются по крайней мере 10.
       FLT_MIN_EXP
Это - самое маленькое возможное значение экспоненты для float типа. Более точно - минимальное отрицательное целое число такое, что значение FLT_RADIX в этой степени минус 1, может представляться как нормализованное число с плавающей запятой float типа.
       DBL_MIN_EXP
       LDBL_MIN_EXP
Они подобны FLT_MIN_EXP, но для double и long double, соответственно.
       FLT_MIN_10_EXP
Это - минимальное отрицательное целое число такое, что 10 в этой степени минус 1, может представляться как нормализованное число с плавающей запятой float типа. Оно, как предполагается, является -37 или даже меньше.
       DBL_MIN_10_EXP
       LDBL_MIN_10_EXP
Они подобны FLT_MIN_10_EXP, но для double и long double, соответственно.
       FLT_MAX_EXP
Это - самое большое возможное значение экспоненты для float типа. Более точно, это - максимальное положительное целое число такое, что значение FLT_RADIX в этой степени минус 1, может представляться как число с плавающей запятой float типа.
       DBL_MAX_EXP
       LDBL_MAX_EXP
Они подобны FLT_MAX_EXP, но для double и long double, соответственно.
       FLT_MAX_10_EXP
Это - максимальное положительное целое число такое, что 10 в этой степени минус 1, может представляться как нормализованное число с плавающей запятой float типа. Оно, как предполагается, является по крайней мере 37.
       DBL_MAX_10_EXP
       LDBL_MAX_10_EXP
Они подобны FLT_MAX_10_EXP, но для double и long double, соответственно.
       FLT_MAX
Значение этой макрокоманды - максимальное число, представимое в float типе. Предполагается что оно по крайней мере 1E + 37. Значение имеет float тип.

Самое маленькое представимое число - -FLT_MAX.

       DBL_MAX
       LDBL_MAX
Они подобны FLT_MAX, но для double и long double, соответственно. Тип значения макрокоманды - такой же как тип, который она описывает.
       FLT_MIN
Значение этой макрокоманды - минимальное нормализованное положительное число с плавающей запятой, которое является представимым в float типе. Предполагается быть не больше, чем 1E-37.
       DBL_MIN
       LDBL_MIN
Они подобны FLT_MIN, но для double и long double, соответственно. Тип значения макрокоманды - такой же как тип, который она описывает.
       FLT_EPSILON
Это - минимальное положительное число с плавающей запятой float типа такое, что 1.0 + FLT_EPSILON != 1.0 является истинным. Предполагается быть не больше чем 1E-5.
       DBL_EPSILON
       LDBL_EPSILON
Они подобны FLT_EPSILON, но для double и long double, соответственно. Тип значения макрокоманды - такой же как тип, который она описывает. Значения, как предполагается, не больше чем 1E-9.

A.5.3.3 ИИЭР(IEEE) числа с плавающей запятой

Вот пример, показывающий, как размеры типа с плавающей запятой выступают в поддержку наиболее общего представления с плавающей запятой, заданного ИИЭР Стандартом для Двоичной Арифметики С плавающей запятой (ANSI/IEEE Std 754-1985). Почти все компьютеры, разработанные начиная с 1980­ ого используют этот формат.

ИИЭР представление float с одинарной точностью использует основание 2. Имеется знаковый разряд, мантисса с 23 битами плюс один скрытый бит (так что общая точность - 24 2-ичные цифры), и экспонента с 8 битами, которая может представлять значения в промежутке от -125 до 128, включительно.

Так, для реализации, которая использует, это представление для типа данных float, соответствующие значения для соответствующих параметров:

                FLT_RADIX        2
                FLT_MANT_DIG     24
                FLT_DIG          6
                FLT_MIN_EXP     -125
                FLT_MIN_10_EXP  -37
                FLT_MAX_EXP      128
                FLT_MAX_10_EXP  +38
                FLT_MIN          1.17549435E-38F
                FLT_MAX          3.40282347E+38F
                FLT_EPSILON      1.19209290E-07F
Имеются значения для типа данных double:
                DBL_MANT_DIG     53
                DBL_DIG          15
                DBL_MIN_EXP     -1021
                DBL_MIN_10_EXP  -307
                DBL_MAX_EXP      1024
                DBL_MAX_10_EXP   308
                DBL_MAX          1.7976931348623157E+308
                DBL_MIN          2.2250738585072014E-308
                DBL_EPSILON      2.2204460492503131E-016

A.5.4 Величина Смещения Поля Структуры

Вы можете использовать offsetof, чтобы измерить расположение внутри структурного типа специфического элемента структуры.

       size_t offsetof (type, member)     (макрос)
Он расширяется до целочисленного постоянного выражения, которое является смещением элемента структуры, именованного member в структурном типе type. Например, offsetof (struct s, elem) - смещение, в байтах, элемента elem в struct s.

Эта макрокоманда не будет работать, если элемент - битовое поле; Вы получаете ошибку из компилятора C в этом случае.


Next Previous Contents