C99 (ранее известного как C9X ) - неофициальное название для ISO / IEC 9899: 1999, предыдущей версии стандарта языка программирования C. Он расширяет предыдущую версию (C90 ) новыми функциями для языка и стандартной библиотеки, а также помогает реализациям лучше использовать доступное компьютерное оборудование, такое как IEEE 754- 1985 Арифметика с плавающей запятой и компиляторная технология. Версия 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, но в некоторых отношениях он строже.
В частности, объявление без спецификатора типа больше не имеет неявного значения int
. Комитет по стандартам C решил, что для компиляторов важнее диагностировать непреднамеренное упущение спецификатора типа, чем молча обрабатывать унаследованный код, основанный на неявном int
. На практике компиляторы, скорее всего, отобразят предупреждение, затем примут значение int
и продолжат перевод программы.
C99 представил несколько новых функций, многие из которых уже были реализованы как расширения в нескольких компиляторах:
long long int
, необязательное расширенное целое число типы, явный логический тип данных и сложный
тип для представления комплексных чисел //
, как в BCPL, C ++ и Java snprintf
<stdbool.h >
, <complex.h >
, <tgmath.h >
и <inttypes.h >
, которые выбирают математическую библиотеку функцию на основе float
, double
или long double
аргументы и т. Д.struct point p = {.x = 1,.y = 2};
)function ((struct x) {1, 2})
)ограничение
квалификация допускает более агрессивную оптимизацию кода , устраняя преимущества доступа к массиву во время компиляции, которыми раньше обладал FORTRAN по сравнению с универсальными именами символов ANSI Cstatic
в индексах массивов в объявлениях параметровЧасти C99 sta ndard включены в текущую версию стандарта C ++, включая целочисленные типы, заголовки и библиотечные функции. Массивы переменной длины не входят в число этих включенных частей, потому что Стандартная библиотека шаблонов C ++ уже включает аналогичные функции.
Основной особенностью C99 является поддержка числовых значений, и в частности поддержка доступа к функциям IEEE 754-1985 ( также известный как IEC 60559) оборудование с плавающей точкой, присутствующее в подавляющем большинстве современных процессоров (определено в «Приложении F IEC 60559 арифметика с плавающей точкой»). Платформы без оборудования IEEE 754 также могут реализовать это в программном обеспечении.
На платформах с плавающей запятой IEEE 754:
float
определяется как IEEE 754 single precision, double
определяется как double precision, а long double
определяется как IEEE 754 расширенная точность (например, Intel 80- бит двойная расширенная точность на платформах x86 или x86-64 ), или некоторая форма четырехкратной точности, если возможно; в противном случае это двойная точность.FLT_EVAL_METHOD | float | double | двойной двойной |
---|---|---|---|
0 | поплавок | двойной | длинный двойной |
1 | двойной | двойной | длинный двойной |
2 | длинный двойной | long double | long double |
FLT_EVAL_METHOD == 2
указывает, что все внутренние промежуточные вычисления выполняются по умолчанию с высокой точностью (long double) там, где это возможно (например, 80-битное двойное расширение ), FLT_EVAL_METHOD == 1
выполняет все внутренние промежуточные выражения с двойной точностью (если только операнд не является long double), тогда как FLT_EVAL_METHOD == 0
указывает, что каждая операция оценивается только с точностью самого широкого операнда каждой операции. rator. Тип промежуточного результата для операндов заданной точности сведен в соседней таблице.FLT_EVAL_METHOD == 2
имеет тенденцию ограничивать риск ошибок округления, влияющих на численно нестабильные выражения (см. Обоснование дизайна IEEE 754 ) и является разработанным методом по умолчанию для оборудования x87, но дает неинтуитивное поведение для неосторожного пользователя; FLT_EVAL_METHOD == 1
изначально использовался метод оценки по умолчанию в KR 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, ведет к специфичному для компилятора поведению; такие несоответствия не допускаются в компиляторах, соответствующих C99 (приложение F).
Следующий аннотированный пример кода C99 для вычисления функции непрерывной дроби демонстрирует основные возможности:
1 #include2 #include 3 #include 4 #include 5 #include 6 #include 7 #include 8 9 double compute_fn (double z) // [1] 10 {11 #pragma STDC FENV_ACCESS ON // [2 ] 12 13 утверждение (FLT_EVAL_METHOD == 2); // [3] 14 15 if (isnan (z)) // [4] 16 put («z не является числом»); 17 18 if (isinf (z)) 19 put («z бесконечно»); 20 21 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] 22 23 feclearexcept (FE_DIVBYZERO); // [7] 24 25 булевых поднято = fetestexcept (FE_OVERFLOW); // [8] 26 27 if (поднят) 28 put ("Непредвиденное переполнение."); 29 30 возврат р; 31} 32 33 int main (void) 34 {35 #ifndef __STDC_IEC_559__ 36 put («Предупреждение: __STDC_IEC_559__ не определено. Плавающая точка IEEE 754 не полностью поддерживается.»); // [9] 37 #endif 38 39 #pragma STDC FENV_ACCESS ON 40 41 #ifdef TEST_NUMERIC_STABILITY_UP 42 fesetround (FE_UPWARD); // [10] 43 #elif TEST_NUMERIC_STABILITY_DOWN 44 fesetround (FE_DOWNWARD); 45 #endif 46 47 printf ("%. 7g \ n", compute_fn (3.0)); 48 printf ("%. 7g \ n", compute_fn (NAN)); 49 50 возврат 0; 51}
Сноски:
gcc -std = c99 -mfpmath = 387 -o test_c99_fp -lm test_c99_fp.c
STDC
, определены в стандарте C.)long double
определяется как двойная расширенная или учетверенная точность IEEE 754, если таковая имеется. Использование более высокой точности, чем требуется для промежуточных вычислений, может минимизировать ошибку округления (typedef double_t
можно использовать для кода, переносимого под всеми FLT_EVAL_METHOD
s).FLT_EVAL_METHOD
определено как 2, тогда все внутренние вычисления, включая константы, будут выполняться с длинной двойной точностью; если FLT_EVAL_METHOD
определено как 0, то для этого необходимы дополнительные меры, включая, возможно, дополнительные приведения типов и явное указание констант как long double.)__STDC_IEC_559__
подлежит определению только если "Приложение F IEC 60559 арифметика с плавающей запятой" полностью реализовано компилятором и библиотекой C (пользователи должны знать, что этот макрос иногда определяется, а не должен быть).TEST_NUMERIC_STABILITY_UP
и т. д. в этом примере при отладке) может использоваться для диагностики числовой нестабильности. Этот метод можно использовать, даже если compute_fn ()
является частью отдельно скомпилированной двоичной библиотеки. Но в зависимости от функции числовые нестабильности не всегда обнаруживаются.Стандартный макрос __STDC_VERSION__
определяется со значением 199901L
, чтобы указать, что C99 поддерживает доступен. Как и в случае с макросом __STDC__
для C90, __STDC_VERSION__
можно использовать для написания кода, который будет по-разному компилироваться для компиляторов C90 и C99, как в этом примере, который гарантирует, что inline
доступен в любом случае (заменив его на static
в C90, чтобы избежать ошибок компоновщика).
#if __STDC_VERSION__>= 199901L / * "inline" - ключевое слово * / #else # define inline static #endif
Большинство компиляторов C обеспечивают поддержку по крайней мере некоторых из представленных функций в C99.
Исторически Microsoft медленно внедряла новые функции C в свои инструменты Visual C ++, вместо этого сосредотачиваясь в основном на поддержке разработок в стандартах C ++. Однако с появлением Visual C ++ 2013 Microsoft реализовала ограниченное подмножество C99, которое было расширено в Visual C ++ 2015.
Компилятор | Уровень поддержки | Сведения о совместимости C99 |
---|---|---|
Acorn C / C ++ | Частично | В официальной документации указано, что поддерживается "большинство" функций компилятора, а также "некоторые" функции библиотеки. |
AMD x86 Open64 Compiler Suite | В основном | Имеет поддержку C99, равную поддержке GCC. |
cc65 | Частичная | Полная C89 и поддержка C99 не реализована, частично из-за ограничений платформы (MOS Technology 6502 ). Поддержка некоторых типов C99, таких как _Complex и 64-битных целых (long long), не планируется. |
Ch | Частично | Поддерживает основные функции C99. |
Clang | В основном | Поддерживает все функции, кроме прагм с плавающей запятой C99. |
CompCert | В основном | Сертифицированный компилятор, формально признанный правильным. Поддерживает все функции, кроме комплексных чисел C99 и VLA, а также незначительные ограничения для операторов switch (no устройство Даффа ). |
cparser | Full | Поддерживает функции C99. |
C ++ Builder | Только в 64-битном режиме, так как последний является вилкой CLang. | |
Digital Mars C / C ++ Compiler | Частично | Отсутствует поддержка некоторых функций, таких как <tgmath.h >и _Pragma. |
GCC | В основном | По состоянию на июнь 2014 г. расширенные идентификаторы, стандартные прагмы и поддержка операций с плавающей запятой IEEE 754 / IEC 60559 отсутствуют в основном GCC. Кроме того, некоторые функции (например, как расширенные целочисленные типы и новые функции библиотеки) должны предоставляться стандартной библиотекой C и выходят за рамки GCC. Выпуски 4.6 и 4.7 GCC также обеспечивают тот же уровень соответствия. Частичная поддержка IEEE 754, даже если оборудование совместимо: могут потребоваться некоторые параметры компилятора, чтобы избежать некорректной оптимизации (например, -std = c99и -fsignaling-nans), но полная поддержка режимов направленного округления отсутствует, даже когда используется -frounding-math. |
Green Hills Software | Полная | |
IBM C для AIX, V6 и XL C / C ++ V11.1 для AIX | Полная | |
IBM Rational logiscope | Полная | До Logiscope 6.3 поддерживались только базовые конструкции C99. C99 официально поддерживается в Logiscope 6.4 и более поздних версиях. |
The Portland Group PGI C / C ++ | Full | |
IAR Systems. Embedded Workbench | В основном | Не поддерживает UCN (универсальные имена символов). Компилятор для встроенных целей, таких как ARM, Coldfire, MSP430, AVR, AVR32, 8051,... Нет целей x86. |
Компилятор Intel C ++ | В основном. | |
Microsoft Visual C ++ | Частично | Visual C ++ 2012 и более ранние версии не поддерживали C99.. Visual C ++ 2013 реализует ограниченное подмножество C99, необходимое для компилировать популярные проекты с открытым исходным кодом.. Visual C ++ 2015 реализует стандартную библиотеку C99, за исключением любых функций библиотеки, которые зависят от функций компилятора, которые еще не поддерживаются компилятором (например, <tgmath.h >не реализовано).. Visual C ++ 2019 (16.6) добавляет дополнительную поддержку препроцессора, совместимого с C99. |
Open Watcom | Partial | Реализует наиболее часто используемые части стандарта. Однако они включаются только с помощью недокументированного переключателя командной строки «-za99». Три функции C99 были объединены как расширения C90, начиная с версии до версии 1.0: комментарии в стиле C ++ (//), гибкие элементы массива, конечная запятая, разрешенная в объявлении перечисления. |
Full | Поддерживает все функции C99. | |
Портативный компилятор C | Частичный | Работа над тем, чтобы стать совместимым с C99. |
Sun Studio | Полная | |
Amsterdam Compiler Kit | No | Интерфейс C99 в настоящее время ведется расследование. |
Tiny C Compiler | Partial | Не поддерживает комплексные числа. Поддерживаются массивы переменной длины, но не в качестве аргументов функций. Разработчики заявляют, что «TCC движется к полному соответствию ISOC99». |
vbcc | Частично |
После ратификации стандарта C 1999 года рабочая группа по стандартам подготовила технические отчеты с указанием улучшенных поддержка встроенной обработки, дополнительных типов символьных данных (поддержка Unicode ) и библиотечных функций с улучшенной проверкой границ . Продолжается работа над техническими отчетами, относящимися к десятичным с плавающей запятой, дополнительным математическим специальным функциям и дополнительным функциям динамического распределения памяти. Комитеты по стандартам C и C ++ совместно работали над спецификациями для многопоточного программирования.
Следующая версия стандарта C, C11, была ратифицирована в 2011 году. Комитет по стандартам C принял руководящие принципы, ограничивающие принятие новых функций, которые не были протестированы существующими реализациями. Много усилий было потрачено на разработку модели памяти, чтобы прояснить точки последовательности и поддерживать многопоточное программирование.
Предшествующие. C89 / C90 / "ANSI C" | язык C стандарты | Преемник. C11 |