С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определяется как расширенная точность Intel IEEE 754 (например, 80-битная двойная расширенная точность на платформах 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  (  двойной   z  )    // [1] 
 { 
         #pragma STDC FENV_ACCESS ON  // [2] 

         утверждать  (  FLT_EVAL_METHOD   ==   2  );     // [3] 

         if   (  isnan  (  z  ))    // [4] 
                 puts  (  «z не число»  ); 

          if   (  isinf  (  z  )) 
                 puts  (  «z бесконечно»  ); 

          длинный   дабл   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] 

         feclearException  (  FE_DIVBYZERO  );     // [7] 

         bool   поднят   =   fetestException  (  FE_OVERFLOW  );     // [8] 

         if   (  поднятый  ) 
                 puts  (  "Непредвиденное переполнение."  ); 

          вернуть   р  ; 
  } 

 int   main  (  void  ) 
 { 
         #ifndef __STDC_IEC_559__ 
         puts  (  «Предупреждение: __STDC_IEC_559__ не определен. IEEE 754 с плавающей запятой не полностью поддерживается.»  );    // [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  )); 

          вернуть   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» — ключевое слово */ 
 #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 Стандарты Преемник