С99

Обложка документа по стандартам C99

C99 (ранее известный как C9X ) — неофициальное название ISO/IEC 9899:1999 , предыдущей версии языка программирования C. стандарта [1] Он расширяет предыдущую версию ( C90 ) новыми функциями языка и стандартной библиотеки и помогает реализациям лучше использовать доступное компьютерное оборудование, такое как IEEE 754-1985 арифметика с плавающей запятой и технология компилятора. [2] Версия C11 стандарта языка программирования C, опубликованная в 2011 году, обновляет C99.

История [ править ]

После того как ANSI разработал официальный стандарт языка программирования C в 1989 году, который стал международным стандартом в 1990 году, спецификация языка C в течение некоторого времени оставалась относительно статичной, в то время как C++ продолжал развиваться, в основном в ходе собственных усилий по стандартизации. Нормативная поправка 1 создала новый стандарт для C в 1995 году, но только для того, чтобы исправить некоторые детали стандарта 1989 года и добавить более широкую поддержку международных наборов символов. Стандарт подвергся дальнейшему пересмотру в конце 1990-х годов, что привело к публикации ISO/IEC 9899:1999 в 1999 году, который был принят в качестве стандарта ANSI в мае 2000 года. Язык, определенный этой версией стандарта, обычно называют « С99». Международный стандарт C поддерживается рабочей группой ISO/IEC JTC1/SC22 /WG14.

Дизайн [ править ]

C99 по большей части обратно совместим с C89, но в некоторых отношениях он более строгий. [3]

В частности, объявление, в котором отсутствует спецификатор типа, больше не имеет int неявно предполагается. Комитет по стандартизации C решил, что для компиляторов более полезно диагностировать непреднамеренное упущение спецификатора типа, чем молча обрабатывать унаследованный код, который полагался на неявные int. На практике компиляторы, скорее всего, выдадут предупреждение, а затем предполагают, что int и продолжаем перевод программы.

C99 представил несколько новых функций, многие из которых уже были реализованы в виде расширений в нескольких компиляторах: [4]

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

Поддержка чисел с плавающей запятой IEEE 754

Основной особенностью C99 является поддержка числовых чисел и, в частности, поддержка доступа к функциям стандарта IEEE 754-1985 (также известного как IEC 60559) аппаратного обеспечения с плавающей запятой , присутствующего в подавляющем большинстве современных процессоров (определенных в «Приложении F»). IEC 60559, арифметика с плавающей запятой»). Платформы без аппаратного обеспечения IEEE 754 также могут реализовать его программно. [2]

На платформах с плавающей запятой IEEE 754:

  • float определяется как IEEE 754 одинарной точности , double определяется как двойная точность и long double определяется как расширенная точность IEEE 754 (например, 80-битная двойная расширенная точность Intel на платформах x86 или x86-64 ) или какая-либо форма четырехкратной точности , если она доступна; в противном случае это двойная точность.
  • Четыре арифметических операции и квадратный корень округляются правильно, как определено стандартом IEEE 754.
    FLT_EVAL_METHOD плавать двойной длинный двойной
    0 плавать двойной длинный двойной
    1 двойной двойной длинный двойной
    2 длинный двойной длинный двойной длинный двойной
  • Оценка выражения определяется для выполнения одним из трех четко определенных методов, указывающих, преобразуются ли сначала переменные с плавающей запятой в более точный формат в выражениях: FLT_EVAL_METHOD == 2 указывает, что все внутренние промежуточные вычисления выполняются по умолчанию с высокой точностью (long double), где это возможно (например, 80-битное double Extended ), FLT_EVAL_METHOD == 1 выполняет все внутренние промежуточные выражения с двойной точностью (если операнд не имеет длину double), в то время как FLT_EVAL_METHOD == 0 указывает, что каждая операция оценивается только с точностью самого широкого операнда каждого оператора. Типы промежуточных результатов для операндов заданной точности приведены в соседней таблице.

FLT_EVAL_METHOD == 2 имеет тенденцию ограничивать риск ошибок округления, влияющих на численно нестабильные выражения (см. обоснование конструкции IEEE 754 ) и является разработанным методом по умолчанию для оборудования x87 , но приводит к неинтуитивному поведению для неосторожного пользователя; [9] FLT_EVAL_METHOD == 1 был методом оценки по умолчанию, первоначально использовавшимся в K&R C , который способствовал удвоению всех чисел с плавающей запятой в выражениях; и FLT_EVAL_METHOD == 0 также широко используется и определяет строгую «оценку типа» операндов. Для gcc ( FLT_EVAL_METHOD == 2 используется по умолчанию для 32-разрядной версии x86, и FLT_EVAL_METHOD == 0 используется по умолчанию в 64-битной версии x86-64, но FLT_EVAL_METHOD == 2 может быть указан на x86-64 с опцией -mfpmath=387.) До C99 компиляторы могли непоследовательно округлять промежуточные результаты, особенно при использовании x87 , что приводило к специфичному для компилятора поведению; аппаратного обеспечения с плавающей запятой [10] такие несоответствия не допускаются в составителях, соответствующих C99 (приложение F).

Пример [ править ]

Следующий аннотированный пример кода C99 для вычисления функции непрерывной дроби демонстрирует основные функции:

#include <stdio.h>
#include <math.h>
#include <float.h>
#include <fenv.h>
#include <tgmath.h>
#include <stdbool.h>
#include <assert.h>

double compute_fn(double z)  // [1]
{
        #pragma STDC FENV_ACCESS ON  // [2]

        assert(FLT_EVAL_METHOD == 2);  // [3]

        if (isnan(z))  // [4]
                puts("z is not a number");

        if (isinf(z))
                puts("z is infinite");

        long double r = 7.0 - 3.0/(z - 2.0 - 1.0/(z - 7.0 + 10.0/(z - 2.0 - 2.0/(z - 3.0)))); // [5, 6]

        feclearexcept(FE_DIVBYZERO);  // [7]

        bool raised = fetestexcept(FE_OVERFLOW);  // [8]

        if (raised)
                puts("Unanticipated overflow.");

        return r;
}

int main(void)
{
        #ifndef __STDC_IEC_559__
        puts("Warning: __STDC_IEC_559__ not defined. IEEE 754 floating point not fully supported."); // [9]
        #endif

        #pragma STDC FENV_ACCESS ON

        #ifdef TEST_NUMERIC_STABILITY_UP
        fesetround(FE_UPWARD);                   // [10]
        #elif TEST_NUMERIC_STABILITY_DOWN
        fesetround(FE_DOWNWARD);
        #endif

        printf("%.7g\n", compute_fn(3.0));
        printf("%.7g\n", compute_fn(NAN));

        return 0;
}

Сноски:

  1. Скомпилировать с помощью: gcc -std=c99 -mfpmath=387 -o test_c99_fp test_c99_fp.c -lm
  2. Поскольку в этой функции манипулируются флагами состояния IEEE 754, эта #pragma необходима, чтобы избежать неправильной перестановки компилятором таких тестов при оптимизации. (Прагмы обычно определяются реализацией, но те, у которых есть префикс STDC определены в стандарте C.)
  3. C99 определяет ограниченное количество методов оценки выражений: можно проверить текущий режим компиляции, чтобы убедиться, что он соответствует предположениям, в соответствии с которыми был написан код.
  4. Специальные значения, такие как NaN и положительная или отрицательная бесконечность, можно проверить и установить.
  5. long double определяется как IEEE 754 с двойной расширенной или учетверенной точностью, если таковая имеется. Использование более высокой точности, чем требуется для промежуточных вычислений, может минимизировать ошибку округления. [11] ( определение типа double_t может использоваться для кода, переносимого под все FLT_EVAL_METHODс).
  6. Основная функция, которую необходимо оценить. Хотя кажется, что некоторые аргументы этой непрерывной дроби, например 3,0, приведут к ошибке деления на ноль, на самом деле функция четко определена для 3,0, и деление на 0 просто вернет +бесконечность, которая тогда будет правильно приводят к конечному результату: IEEE 754 по умолчанию не перехватывает такие исключения и спроектирован таким образом, что их очень часто можно игнорировать, как в этом случае. (Если FLT_EVAL_METHOD определяется как 2, то все внутренние вычисления, включая константы, будут выполняться с двойной точностью; если FLT_EVAL_METHOD определяется как 0, то для обеспечения этого требуется дополнительная осторожность, включая, возможно, дополнительные приведения и явное указание констант как long double.)
  7. Поскольку поднятый флаг деления на ноль в этом случае не является ошибкой, его можно просто убрать, чтобы очистить флаг для использования в более позднем коде.
  8. В некоторых случаях как ошибку можно рассматривать и другие исключения, например переполнение (хотя на самом деле можно показать, что в данном случае этого произойти не может).
  9. __STDC_IEC_559__ должен быть определен только в том случае, если «Арифметика с плавающей запятой по Приложению F IEC 60559» полностью реализована компилятором и библиотекой C (пользователи должны знать, что этот макрос иногда определяется, хотя это не должно быть).
  10. Режим округления по умолчанию — округление до ближайшего (с правилом четного округления в промежуточных случаях) для IEEE 754, но явно устанавливая режим округления в сторону + и - бесконечности (путем определения TEST_NUMERIC_STABILITY_UP и т. д. в этом примере при отладке) можно использовать для диагностики числовой нестабильности. [12] Этот метод можно использовать, даже если compute_fn() является частью отдельно скомпилированной двоичной библиотеки. Но в зависимости от функции числовые нестабильности не всегда могут быть обнаружены.

Определение версии [ править ]

Стандартный макрос __STDC_VERSION__ определяется значением 199901L чтобы указать, что доступна поддержка C99. Как и в случае __STDC__ макрос для С90, __STDC_VERSION__ может использоваться для написания кода, который будет компилироваться по-разному для компиляторов C90 и C99, как в этом примере, который гарантирует, что inline доступен в любом случае (заменив его на static в C90, чтобы избежать ошибок компоновщика).

#if __STDC_VERSION__ >= 199901L
  /* "inline" is a keyword */
#else
# define inline static
#endif

Реализации [ править ]

Большинство компиляторов C обеспечивают поддержку по крайней мере некоторых функций, представленных в C99.

Исторически сложилось так, что Microsoft не спешила с внедрением новых функций C в свои инструменты Visual C++ , вместо этого сосредотачиваясь главным образом на поддержке разработок в стандартах C++. [13] Однако с выпуском Visual C++ 2013 Microsoft реализовала ограниченное подмножество C99, которое было расширено в Visual C++ 2015. [14]

Будущая работа [ править ]

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

Следующая версия стандарта C, C11 , была ратифицирована в 2011 году. [41] Комитет по стандартизации C принял рекомендации, которые ограничивали внедрение новых функций, которые не были протестированы существующими реализациями. Много усилий было потрачено на разработку модели памяти , чтобы уточнить точки последовательности и поддержать многопоточное программирование.

См. также [ править ]

Ссылки [ править ]

  1. ^ «ISO/IEC 9899:1999 – Языки программирования – C» . Исо.орг. 8 декабря 2011 года . Проверено 8 апреля 2014 г.
  2. Перейти обратно: Перейти обратно: а б «Поддержка IEEE 754 в C99» (PDF) . grouper.ieee.org . Архивировано из оригинала (PDF) 28 октября 2017 года . Проверено 15 июля 2021 г.
  3. ^ «Стандарты — использование коллекции компиляторов GNU (GCC)» . Gcc.gnu.org . Проверено 8 апреля 2014 г.
  4. ^ «Параметры диалекта C — использование коллекции компиляторов GNU (GCC)» . Gcc.gnu.org. 6 мая 2009 года . Проверено 8 апреля 2014 г.
  5. ^ «Использование коллекции компиляторов GNU (GCC): назначенные инициализаторы» . gnu.org . Проверено 18 сентября 2019 г.
  6. ^ «Использование коллекции компиляторов GNU (GCC): составные литералы» . gnu.org . Проверено 31 января 2016 г.
  7. ^ Ульрих Дреппер (23 октября 2007 г.). «Что должен знать каждый программист о памяти» . LWN.net . Проверено 3 апреля 2015 г.
  8. ^ Спецификация ISO/IEC 9899:1999, TC3 (PDF) . п. 119, § 6.7.5.3 Деклараторы функций (включая прототипы), абз. 7.
  9. ^ Дуг Прист (1997). «Различия между реализациями IEEE 754» .
  10. ^ Джек Вёр (1 ноября 1997 г.). «Разговор с Уильямом Каханом» .
  11. ^ Уильям Кахан (11 июня 1996 г.). «Пагубное влияние компьютерных тестов на прикладную математику, физику и химию» (PDF) .
  12. ^ Уильям Кахан (11 января 2006 г.). «Насколько бесполезны бессмысленные оценки округления в вычислениях с плавающей запятой?» (PDF) .
  13. ^ Питер Брайт (29 июня 2013 г.). «C99 наконец-то признан, поскольку Microsoft прокладывает путь к C++14» . Арс Техника . Проверено 9 января 2015 г.
  14. Перейти обратно: Перейти обратно: а б с Бреннер, Пэт. «Что нового в Visual C++ в Visual Studio 2015» . Сеть разработчиков Microsoft . Проверено 27 апреля 2015 г.
  15. ^ «Использование компилятора Open64 для x86» (PDF) . Разработчик.amd.com. Архивировано (PDF) из оригинала 24 января 2022 года . Проверено 2 марта 2022 г.
  16. ^ «cc65 — бесплатный компилятор C для систем на базе 6502» . Проверено 14 сентября 2011 г.
  17. ^ «Возможности интерпретатора C/C++ Ch C99» . SoftIntegration, Inc. 15 февраля 2008 г. Проверено 15 февраля 2008 г.
  18. ^ «Руководство пользователя компилятора Clang» . Проверено 14 октября 2017 г.
  19. ^ «Документация компилятора и руководство пользователя, проверенные CompCert C (версия 3.10)» . 19 ноября 2021 г. Проверено 3 марта 2022 г.
  20. ^ "домашняя страница libfirm" . Проверено 4 февраля 2014 г.
  21. ^ «Реализация языка C — Digital Mars» . Проверено 14 сентября 2011 г.
  22. ^ «Состояние функций C99 в GCC» . Фонд свободного программного обеспечения, Inc., 28 июля 2021 г. Проверено 13 августа 2021 г.
  23. ^ «Состояние функций C99 в GCC 4.6» . Фонд свободного программного обеспечения, Inc., 23 мая 2013 г. Проверено 23 мая 2013 г.
  24. ^ «Состояние функций C99 в GCC 4.7» . Фонд свободного программного обеспечения, Inc., 23 мая 2013 г. Проверено 23 мая 2013 г.
  25. ^ «Семантика вычислений с плавающей запятой в GCC» . 20 июля 2018 года . Проверено 12 августа 2018 г.
  26. ^ «IBM C для AIX, V6.0 теперь поддерживает стандарт C99» . 2 июля 2002 года . Проверено 31 января 2016 г.
  27. ^ «IBM-XL C/C++ для AIX» . Проверено 31 января 2016 г.
  28. ^ «Поддержка IBM Rational Logiscope для стандарта C99 — США» . 24 февраля 2012 года . Проверено 31 января 2016 г.
  29. ^ «Вопросы и ответы читателей: А как насчет VC++ и C99?» . Мельница Саттера . 3 мая 2012 года . Проверено 31 января 2016 г.
  30. ^ «A.27 Использование массивов переменной длины C99» . Майкрософт . Проверено 31 января 2016 г.
  31. ^ «Разработчики Microsoft для C99: используйте ISO C++» . ИнфоQ . Проверено 31 января 2016 г.
  32. ^ «Поддержка библиотеки C99 в Visual Studio 2013» . Майкрософт. 19 июля 2013 года . Проверено 31 января 2016 г.
  33. ^ «Функции, исправления и критические изменения STL C++11/14 в VS 2013» . Блоги.msdn.com. 28 июня 2013 года . Проверено 8 апреля 2014 г.
  34. ^ «Объявление о полной поддержке препроцессора, соответствующего C/C++, в MSVC» . Майкрософт. 27 марта 2020 г. Проверено 17 сентября 2020 г.
  35. ^ «Соответствие C99 в Open Watcom» . Архивировано из оригинала 3 мая 2015 года . Проверено 25 сентября 2015 г.
  36. ^ «Обзор Пеллеса С» . Январь 2013. Архивировано из оригинала 13 марта 2022 года . Проверено 2 марта 2022 г.
  37. ^ «Sun Studio 12: Ознакомительные сведения о компиляторе C 5.9» . Sun Microsystems, Inc., 31 мая 2007 г. Проверено 23 сентября 2012 г.
  38. ^ «Справочная документация по компилятору Tiny C» . Проверено 31 января 2016 г.
  39. ^ проекта, Согласно списку TODO сложные типы — единственная недостающая функция C99. Массивы переменной длины были добавлены в TCC 0.9.26 [1]
  40. ^ «TCC: Tiny C Compiler» . Проверено 31 января 2016 г.
  41. ^ «Стандарты — использование коллекции компиляторов GNU (GCC)» . Gcc.gnu.org . Проверено 8 апреля 2014 г.

Дальнейшее чтение [ править ]

Внешние ссылки [ править ]

Предшественник языка C Стандарты Преемник