Открыть сервис

C11

C11 (также известный как ISO/IEC 9899:2011) — это стандарт языка программирования C, принятый Международной организацией по стандартизации (ISO) и Международной электротехнической комиссией (IEC) в декабре 2011 года. Он пришёл на смену стандарту C99 (ISO/IEC 9899:1999) и стал третьей крупной редакцией спецификации языка C. Основными целями C11 были исправление недостатков предыдущего стандарта, улучшение поддержки многопоточности и унификация поведения компиляторов.

История разработки

Работа над новым стандартом началась в 2007 году под руководством рабочей группы ISO/IEC JTC1/SC22/WG14. Первоначально проект назывался C1X, и его планировали завершить к 2010 году, однако процесс затянулся. Основные споры вызвали вопросы, связанные с моделью памяти для многопоточных вычислений, поддержкой атомарных операций и удалением устаревших возможностей. Окончательная версия была одобрена 8 декабря 2011 года и опубликована как ISO/IEC 9899:2011.

В 2018 году вышло техническое исправление (TC1), которое уточнило некоторые формулировки, но не внесло существенных изменений. В 2024 году C11 был заменён стандартом C23 (ISO/IEC 9899:2024), однако остаётся широко используемым в промышленной разработке, особенно в системах реального времени и встраиваемых устройствах.

Основные нововведения

Многопоточность и атомарные операции

C11 ввёл в стандарт встроенную поддержку многопоточности через заголовочный файл <threads.h>, который предоставляет функции для создания и управления потоками (thrd_create, thrd_join), мьютексы (mtx_t), условные переменные (cnd_t) и механизмы синхронизации. Кроме того, добавлен заголовок <stdatomic.h> с атомарными типами (atomic_int, atomic_flag) и операциями (atomic_store, atomic_load, atomic_compare_exchange_strong). Это позволило писать переносимый многопоточный код без привязки к конкретным API операционных систем, таким как POSIX threads.

Универсальные макросы (_Generic)

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

Анонимные структуры и объединения

C11 разрешил вложенные безымянные структуры и объединения, что упростило доступ к полям. Например, если структура содержит анонимную вложенную структуру, её поля становятся доступны напрямую, без указания имени промежуточной структуры. Это улучшило читаемость кода при работе с битовыми полями и сложными типами данных.

Улучшенная поддержка статических утверждений

Добавлен макрос _Static_assert, который позволяет проверять условия на этапе компиляции. Если условие ложно, компилятор выдаёт сообщение об ошибке. Это используется для проверки размеров типов, выравнивания и других константных выражений, что повышает надёжность кода.

Анализ границ массивов

Введено ключевое слово static в объявлениях параметров-массивов для указания минимального размера. Например, void f(int a[static 10]) сообщает компилятору, что массив должен содержать как минимум 10 элементов, что позволяет проводить более строгую оптимизацию и проверки.

Удаление устаревших возможностей

Из стандарта были исключены некоторые функции, признанные опасными или устаревшими. В частности, функция gets() была полностью удалена из-за отсутствия контроля границ буфера, что делало её источником уязвимостей переполнения буфера. Также были помечены как устаревшие (deprecated) некоторые функции из <string.h> (strcpy, strcat), хотя они остались в стандарте.

Изменения в модели памяти

C11 формализовал модель памяти для многопоточных программ, основанную на подходах, разработанных в проекте C++11. Модель определяет, как потоки взаимодействуют через общую память, и устанавливает правила для атомарных операций и барьеров памяти. Введены шесть уровней упорядочения доступа к памяти: от свободного (memory_order_relaxed) до строго последовательного (memory_order_seq_cst). Это позволило компиляторам выполнять оптимизации, сохраняя корректность многопоточного кода.

Совместимость с C99

C11 сохранил обратную совместимость с C99, за исключением удаления функции gets(). Большинство программ, написанных на C99, могут быть скомпилированы с поддержкой C11 без изменений. Однако некоторые возможности, такие как переменные массивы переменной длины (VLA), стали опциональными. В C11 они не обязательны для реализации, хотя многие компиляторы (например, GCC и Clang) продолжают их поддерживать.

Реализации и поддержка

Основные компиляторы языка C (GCC, Clang, MSVC, ICC) поддерживают C11, хотя степень полноты реализации различается. GCC полностью поддерживает стандарт начиная с версии 4.7, Clang — с версии 3.1. В MSVC поддержка C11 была добавлена в Visual Studio 2019, но с ограничениями: например, <threads.h> и <stdatomic.h> реализованы не полностью. Встраиваемые компиляторы (IAR, ARM) также поддерживают C11, часто с урезанными библиотеками.

Критика

Некоторые разработчики критиковали C11 за излишнюю сложность модели памяти, которая требует глубокого понимания для корректного использования. Кроме того, реализация <threads.h> в ряде компиляторов оказалась неполной или неэффективной, что привело к тому, что многие проекты продолжили использовать POSIX threads или платформозависимые API. Также отмечалось, что удаление VLA из обязательных возможностей усложнило перенос кода, написанного для C99.

Применение

C11 используется в операционных системах (ядро Linux, FreeBSD), встраиваемых системах, микроконтроллерах, системах реального времени, а также в библиотеках и приложениях, требующих высокой производительности и переносимости. Стандарт особенно востребован в проектах, где важна многопоточность и атомарные операции, например, в игровых движках, базах данных и сетевых протоколах.

См. также

  • C99
  • C23
  • C++11
  • Модель памяти (программирование)

BFOmetr — база данных и аналитика по компаниям России.

На главную BFOmetr →