C99 - C99

Обложка стандарта 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 года. Язык, определенный в этой версии стандарта, обычно называют " C99 ". Международный стандарт 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:

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

 1 #включают <stdio.h> 2 #включают <math.h> 3 #включают <float.h> 4 #включают <fenv.h> 5 #включают <tgmath.h> 6 #включают <stdbool.h> 7 #включают <assert.h> 8  9 двойной compute_fn(двойной z)  // [1]10 {11         #pragma STDC FENV_ACCESS ON // [2]12 13         утверждать(FLT_EVAL_METHOD == 2);  // [3]14 15         если (Иснан(z))  // [4]16                 ставит("z не число");17 18         если (isinf(z))19                 ставит("z бесконечно");20 21         длинный двойной р = 7.0 - 3.0/(z - 2.0 - 1.0/(z - 7.0 + 10.0/(z - 2.0 - 2.0/(z - 3.0)))); // [5, 6]22 23         очищаться, кроме(FE_DIVBYZERO);  // [7]24 25         bool поднятый = праздник, кроме(FE_OVERFLOW);  // [8]26 27         если (поднятый)28                 ставит(«Непредвиденное переполнение».);29 30         возвращаться р;31 }32 33 int главный(пустота)34 {35         #ifndef __STDC_IEC_559__36         ставит(«Предупреждение: __STDC_IEC_559__ не определено. Плавающая точка IEEE 754 не полностью поддерживается».); // [9]37         #endif38 39         #pragma STDC FENV_ACCESS ON40 41         #ifdef TEST_NUMERIC_STABILITY_UP42         fesetround(FE_UPWARD);                   // [10]43         #elif TEST_NUMERIC_STABILITY_DOWN44         fesetround(FE_DOWNWARD);45         #endif46 47         printf("% .7g п", compute_fn(3.0));48         printf("% .7g п", compute_fn(NAN));49 50         возвращаться 0;51 }

Сноски:

  1. Скомпилировать с помощью: gcc -std=c99 -mfpmath=387 -o test_c99_fp -lm test_c99_fp.c
  2. Поскольку в этой функции используются флаги состояния IEEE 754, эта #pragma необходима, чтобы избежать неправильного изменения компилятором таких тестов при оптимизации. (Прагмы обычно определяются реализацией, но с префиксом STDC определены в стандарте C.)
  3. C99 определяет ограниченное количество методов оценки выражений: текущий режим компиляции можно проверить, чтобы убедиться, что он соответствует предположениям, в соответствии с которыми был написан код.
  4. Особые значения, такие как NaN можно проверить и установить положительную или отрицательную бесконечность.
  5. длинный двойной определяется как IEEE 754 с двойным расширением или с четырехкратной точностью, если доступно. Использование более высокой точности, чем требуется для промежуточных вычислений, может минимизировать ошибка округления[11]typedef 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__ должен быть определен только в том случае, если "Арифметика с плавающей запятой МЭК 60559 Приложение F" полностью реализована компилятором и библиотекой C (пользователи должны знать, что этот макрос иногда определяется, а не должен).
  10. Режим округления по умолчанию - округление до ближайшего (с правилом равного округления в полусредних случаях) для IEEE 754, но явная установка режима округления в сторону + и - бесконечности (путем определения TEST_NUMERIC_STABILITY_UP и т.д. в этом примере при отладке) может использоваться для диагностики числовой нестабильности.[12] Этот метод можно использовать, даже если compute_fn () является частью отдельно скомпилированной двоичной библиотеки. Но в зависимости от функции числовые нестабильности не всегда обнаруживаются.

Обнаружение версии

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

#if __STDC_VERSION__> = 199901L  / * "inline" - ключевое слово * /#еще# определить встроенный статический#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». Iso.org. 8 декабря 2011 г.. Получено 8 апреля 2014.
  2. ^ а б http://grouper.ieee.org/groups/754/meeting-materials/2001-07-18-c99.pdf
  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». Ars Technica. Получено 9 января 2015.
  14. ^ а б c Бреннер, Пат. «Что нового для Visual C ++ в Visual Studio 2015». Сеть разработчиков Microsoft. Получено 27 апреля 2015.
  15. ^ "x86 Open64". Developer.amd.com. 1 апреля 1989 г. Архивировано с оригинал 3 мая 2009 г.. Получено 8 июн 2009.
  16. ^ "cc65 - бесплатный компилятор C для систем на базе 6502". Получено 14 сентября 2011.
  17. ^ "Возможности интерпретатора C / C ++ Ch C99". SoftIntegration, Inc. 15 февраля 2008 г.. Получено 15 февраля 2008.
  18. ^ "Руководство пользователя компилятора Clang". Получено 14 октября 2017.
  19. ^ "Документация по CompCert C и руководство пользователя v2.5". Получено 12 сентября 2015.
  20. ^ "домашняя страница libfirm". Получено 4 февраля 2014.
  21. ^ «Реализация языка C - Цифровой Марс». Получено 14 сентября 2011.
  22. ^ «Статус функций C99 в GCC». Free Software Foundation, Inc. 12 июня 2014 г.. Получено 25 августа 2014.
  23. ^ «Статус функций C99 в GCC 4.6». Free Software Foundation, Inc. 23 мая 2013 г.. Получено 23 мая 2013.
  24. ^ «Статус функций C99 в GCC 4.7». Free Software Foundation, Inc. 23 мая 2013 г.. Получено 23 мая 2013.
  25. ^ «Семантика математики с плавающей запятой в GCC». 20 июля 2018 г.. Получено 12 августа 2018.
  26. ^ «IBM C для AIX, V6.0 теперь поддерживает стандарт C99». Получено 31 января 2016.
  27. ^ «IBM - XL C / C ++ для AIX». Получено 31 января 2016.
  28. ^ «Поддержка IBM Rational Logiscope стандарта C99 - США». Получено 31 января 2016.
  29. ^ «Вопросы и ответы читателя: А как насчет VC ++ и C99?». Sutter’s Mill. Получено 31 января 2016.
  30. ^ «A.27 Использование массивов переменной длины C99». Microsoft. Получено 31 января 2016.
  31. ^ «Разработчики Microsoft для C99: используйте ISO C ++». InfoQ. Получено 31 января 2016.
  32. ^ «Поддержка библиотеки C99 в Visual Studio 2013». Microsoft. Получено 31 января 2016.
  33. ^ «Возможности, исправления и критические изменения C ++ 11/14 STL в VS 2013 - Блог группы разработчиков Visual C ++ - Домашняя страница сайта - Блоги MSDN». Blogs.msdn.com. 28 июня 2013 г.. Получено 8 апреля 2014.
  34. ^ «Объявление о полной поддержке препроцессора, совместимого с C / C ++, в MSVC». Microsoft. 27 марта 2020 г.. Получено 17 сентября 2020.
  35. ^ «Соответствие C99 в Open Watcom». Архивировано из оригинал 3 мая 2015 г.. Получено 25 сентября 2015.
  36. ^ "Обзор Pelles C". Январь 2013.
  37. ^ "Sun Studio 12: ознакомительные сведения о компиляторе C 5.9". Sun Microsystems, Inc. 31 мая 2007 г.. Получено 23 сентября 2012.
  38. ^ "Справочная документация по компилятору Tiny C". Получено 31 января 2016.
  39. ^ Согласно проекту Список дел комплексные типы - единственная отсутствующая функция C99. Массивы переменной длины были добавлены в TCC 0.9.26 [1]
  40. ^ «TCC: Tiny C Compiler». Получено 31 января 2016.
  41. ^ «Стандарты - Использование коллекции компиляторов GNU (GCC)». Gcc.gnu.org. Получено 8 апреля 2014.

дальнейшее чтение

внешняя ссылка

Предшествует
C89 / C90 / "ANSI C"
Язык C стандартыПреемник
C11