С99
Отсутствует информация о _Pragma(), FP_CONTRACT, CX_LIMITED_RANGE. ( ноябрь 2020 г. ) |
Версии языка C |
---|
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]
- встроенные функции
- смешанные объявления и код: объявление переменной больше не ограничивается областью файла или началом составного оператора (блока)
- несколько новых типов данных , в том числе
long long int
, необязательные расширенные целочисленные типы, явный логический тип данных иcomplex
введите для представления комплексных чисел - массивы переменной длины (хотя впоследствии в C11 они были отнесены к условной функции, которую реализации не обязаны поддерживать)
- гибкие члены массива
- поддержка однострочных комментариев, начинающихся с
//
, как в BCPL , C++ и Java - новые библиотечные функции, такие как
snprintf
- новые заголовки , такие как
<stdbool.h>
,<complex.h>
,<tgmath.h>
, и<inttypes.h>
- общие математические (макро) функции, в
<tgmath.h>
, которые выбирают математической библиотеки функцию на основеfloat
,double
, илиlong double
аргументы и т. д. - улучшенная поддержка IEEE с плавающей запятой
- назначенные инициализаторы (например, инициализация структуры по именам полей:
struct point p = { .x = 1, .y = 2 };
) [5] - составные литералы (например, можно создавать структуры при вызовах функций:
function((struct x) {1, 2})
) [6] - поддержка вариативных макросов (макросов с переменным количеством аргументов)
restrict
квалификация позволяет более агрессивно оптимизировать код , устраняя преимущества доступа к массиву во время компиляции, которые ранее были у FORTRAN по сравнению с ANSI C. [7]- универсальные имена символов, которые позволяют пользовательским переменным содержать символы, отличные от стандартного набора символов: четырехзначные.
\u0040
или восьмизначные шестнадцатеричные последовательности\U0001f431
- ключевое слово
static
в индексах массива в объявлениях параметров [8]
Части стандарта 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;
}
Сноски:
- Скомпилировать с помощью:
gcc -std=c99 -mfpmath=387 -o test_c99_fp test_c99_fp.c -lm
- Поскольку в этой функции манипулируются флагами состояния IEEE 754, эта #pragma необходима, чтобы избежать неправильной перестановки компилятором таких тестов при оптимизации. (Прагмы обычно определяются реализацией, но те, у которых есть префикс
STDC
определены в стандарте C.) - C99 определяет ограниченное количество методов оценки выражений: можно проверить текущий режим компиляции, чтобы убедиться, что он соответствует предположениям, в соответствии с которыми был написан код.
- Специальные значения, такие как NaN и положительная или отрицательная бесконечность, можно проверить и установить.
long double
определяется как IEEE 754 с двойной расширенной или учетверенной точностью, если таковая имеется. Использование более высокой точности, чем требуется для промежуточных вычислений, может минимизировать ошибку округления. [11] ( определение типаdouble_t
может использоваться для кода, переносимого под всеFLT_EVAL_METHOD
с).- Основная функция, которую необходимо оценить. Хотя кажется, что некоторые аргументы этой непрерывной дроби, например 3,0, приведут к ошибке деления на ноль, на самом деле функция четко определена для 3,0, и деление на 0 просто вернет +бесконечность, которая тогда будет правильно приводят к конечному результату: IEEE 754 по умолчанию не перехватывает такие исключения и спроектирован таким образом, что их очень часто можно игнорировать, как в этом случае. (Если
FLT_EVAL_METHOD
определяется как 2, то все внутренние вычисления, включая константы, будут выполняться с двойной точностью; еслиFLT_EVAL_METHOD
определяется как 0, то для обеспечения этого требуется дополнительная осторожность, включая, возможно, дополнительные приведения и явное указание констант как long double.) - Поскольку поднятый флаг деления на ноль в этом случае не является ошибкой, его можно просто убрать, чтобы очистить флаг для использования в более позднем коде.
- В некоторых случаях как ошибку можно рассматривать и другие исключения, например переполнение (хотя на самом деле можно показать, что в данном случае этого произойти не может).
__STDC_IEC_559__
должен быть определен только в том случае, если «Арифметика с плавающей запятой по Приложению F IEC 60559» полностью реализована компилятором и библиотекой C (пользователи должны знать, что этот макрос иногда определяется, хотя это не должно быть).- Режим округления по умолчанию — округление до ближайшего (с правилом четного округления в промежуточных случаях) для 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]
Компилятор | Уровень поддержки | Подробности совместимости с C99 |
---|
Будущая работа [ править ]
С момента ратификации стандарта C 1999 года рабочая группа по стандартизации подготовила технические отчеты, в которых определялась улучшенная поддержка встроенной обработки, дополнительные символьные типы данных ( поддержка Unicode ) и библиотечные функции с улучшенной проверкой границ . Продолжается работа над техническими отчетами, касающимися десятичных чисел с плавающей запятой , дополнительных математических специальных функций и дополнительных динамического распределения памяти функций . Комитеты по стандартизации C и C++ совместно работают над спецификациями многопоточного программирования.
Следующая версия стандарта C, C11 , была ратифицирована в 2011 году. [41] Комитет по стандартизации C принял рекомендации, которые ограничивали внедрение новых функций, которые не были протестированы существующими реализациями. Много усилий было потрачено на разработку модели памяти , чтобы уточнить точки последовательности и поддержать многопоточное программирование.
См. также [ править ]
- C++23 , C++20 , C++17 , C++14 , C++11 , C++03 , C++98 , версии стандарта языка программирования C++.
- Совместимость C и C++
- Технический отчет C++ 1
- С плавающей запятой для дальнейшего обсуждения использования оборудования IEEE 754.
Ссылки [ править ]
- ^ «ISO/IEC 9899:1999 – Языки программирования – C» . Исо.орг. 8 декабря 2011 года . Проверено 8 апреля 2014 г.
- ↑ Перейти обратно: Перейти обратно: а б «Поддержка IEEE 754 в C99» (PDF) . grouper.ieee.org . Архивировано из оригинала (PDF) 28 октября 2017 года . Проверено 15 июля 2021 г.
- ^ «Стандарты — использование коллекции компиляторов GNU (GCC)» . Gcc.gnu.org . Проверено 8 апреля 2014 г.
- ^ «Параметры диалекта C — использование коллекции компиляторов GNU (GCC)» . Gcc.gnu.org. 6 мая 2009 года . Проверено 8 апреля 2014 г.
- ^ «Использование коллекции компиляторов GNU (GCC): назначенные инициализаторы» . gnu.org . Проверено 18 сентября 2019 г.
- ^ «Использование коллекции компиляторов GNU (GCC): составные литералы» . gnu.org . Проверено 31 января 2016 г.
- ^ Ульрих Дреппер (23 октября 2007 г.). «Что должен знать каждый программист о памяти» . LWN.net . Проверено 3 апреля 2015 г.
- ^ Спецификация ISO/IEC 9899:1999, TC3 (PDF) . п. 119, § 6.7.5.3 Деклараторы функций (включая прототипы), абз. 7.
- ^ Дуг Прист (1997). «Различия между реализациями IEEE 754» .
- ^ Джек Вёр (1 ноября 1997 г.). «Разговор с Уильямом Каханом» .
- ^ Уильям Кахан (11 июня 1996 г.). «Пагубное влияние компьютерных тестов на прикладную математику, физику и химию» (PDF) .
- ^ Уильям Кахан (11 января 2006 г.). «Насколько бесполезны бессмысленные оценки округления в вычислениях с плавающей запятой?» (PDF) .
- ^ Питер Брайт (29 июня 2013 г.). «C99 наконец-то признан, поскольку Microsoft прокладывает путь к C++14» . Арс Техника . Проверено 9 января 2015 г.
- ↑ Перейти обратно: Перейти обратно: а б с Бреннер, Пэт. «Что нового в Visual C++ в Visual Studio 2015» . Сеть разработчиков Microsoft . Проверено 27 апреля 2015 г.
- ^ «Использование компилятора Open64 для x86» (PDF) . Разработчик.amd.com. Архивировано (PDF) из оригинала 24 января 2022 года . Проверено 2 марта 2022 г.
- ^ «cc65 — бесплатный компилятор C для систем на базе 6502» . Проверено 14 сентября 2011 г.
- ^ «Возможности интерпретатора C/C++ Ch C99» . SoftIntegration, Inc. 15 февраля 2008 г. Проверено 15 февраля 2008 г.
- ^ «Руководство пользователя компилятора Clang» . Проверено 14 октября 2017 г.
- ^ «Документация компилятора и руководство пользователя, проверенные CompCert C (версия 3.10)» . 19 ноября 2021 г. Проверено 3 марта 2022 г.
- ^ "домашняя страница libfirm" . Проверено 4 февраля 2014 г.
- ^ «Реализация языка C — Digital Mars» . Проверено 14 сентября 2011 г.
- ^ «Состояние функций C99 в GCC» . Фонд свободного программного обеспечения, Inc., 28 июля 2021 г. Проверено 13 августа 2021 г.
- ^ «Состояние функций C99 в GCC 4.6» . Фонд свободного программного обеспечения, Inc., 23 мая 2013 г. Проверено 23 мая 2013 г.
- ^ «Состояние функций C99 в GCC 4.7» . Фонд свободного программного обеспечения, Inc., 23 мая 2013 г. Проверено 23 мая 2013 г.
- ^ «Семантика вычислений с плавающей запятой в GCC» . 20 июля 2018 года . Проверено 12 августа 2018 г.
- ^ «IBM C для AIX, V6.0 теперь поддерживает стандарт C99» . 2 июля 2002 года . Проверено 31 января 2016 г.
- ^ «IBM-XL C/C++ для AIX» . Проверено 31 января 2016 г.
- ^ «Поддержка IBM Rational Logiscope для стандарта C99 — США» . 24 февраля 2012 года . Проверено 31 января 2016 г.
- ^ «Вопросы и ответы читателей: А как насчет VC++ и C99?» . Мельница Саттера . 3 мая 2012 года . Проверено 31 января 2016 г.
- ^ «A.27 Использование массивов переменной длины C99» . Майкрософт . Проверено 31 января 2016 г.
- ^ «Разработчики Microsoft для C99: используйте ISO C++» . ИнфоQ . Проверено 31 января 2016 г.
- ^ «Поддержка библиотеки C99 в Visual Studio 2013» . Майкрософт. 19 июля 2013 года . Проверено 31 января 2016 г.
- ^ «Функции, исправления и критические изменения STL C++11/14 в VS 2013» . Блоги.msdn.com. 28 июня 2013 года . Проверено 8 апреля 2014 г.
- ^ «Объявление о полной поддержке препроцессора, соответствующего C/C++, в MSVC» . Майкрософт. 27 марта 2020 г. Проверено 17 сентября 2020 г.
- ^ «Соответствие C99 в Open Watcom» . Архивировано из оригинала 3 мая 2015 года . Проверено 25 сентября 2015 г.
- ^ «Обзор Пеллеса С» . Январь 2013. Архивировано из оригинала 13 марта 2022 года . Проверено 2 марта 2022 г.
- ^ «Sun Studio 12: Ознакомительные сведения о компиляторе C 5.9» . Sun Microsystems, Inc., 31 мая 2007 г. Проверено 23 сентября 2012 г.
- ^ «Справочная документация по компилятору Tiny C» . Проверено 31 января 2016 г.
- ^ проекта, Согласно списку TODO сложные типы — единственная недостающая функция C99. Массивы переменной длины были добавлены в TCC 0.9.26 [1]
- ^ «TCC: Tiny C Compiler» . Проверено 31 января 2016 г.
- ^ «Стандарты — использование коллекции компиляторов GNU (GCC)» . Gcc.gnu.org . Проверено 8 апреля 2014 г.
Дальнейшее чтение [ править ]
- N1256 (окончательный проект стандарта C99 плюс TC1, TC2, TC3); РГ14; 2007 г. ( версии HTML и ASCII )
- ISO/IEC 9899:1999 (официальный стандарт C99); ИСО ; 1999.
- Обоснование C99 ; РГ14; 2003.
- Ченг, Гарри (1 марта 2002 г.). «C99 и числовые вычисления» . Журнал доктора Добба .
- Зеебах, Питер (24 марта 2004 г.). «Разработка с открытым исходным кодом с использованием C99» . РазработчикWorks . ИБМ .