stringtranslate.com

С (язык программирования)

C ( произносится как / ˈs / – как буква c ) [6]язык программирования общего назначения . Он был создан в 1970-х годах Деннисом Ритчи и по-прежнему широко используется и оказывает влияние. По своей конструкции возможности C четко отражают возможности целевых процессоров. Он нашел прочное применение в коде операционных систем (особенно в ядрах [7] ), драйверах устройств и стеках протоколов , но его использование в прикладном программном обеспечении сокращается. [8] C обычно используется в компьютерных архитектурах, которые варьируются от крупнейших суперкомпьютеров до самых маленьких микроконтроллеров и встраиваемых систем .

Преемник языка программирования B , C был первоначально разработан в Bell Labs Ричи между 1972 и 1973 годами для создания утилит, работающих на Unix . Он был применен для повторной реализации ядра операционной системы Unix. [9] В течение 1980-х годов C постепенно набирал популярность. Он стал одним из наиболее широко используемых языков программирования, [10] [11] с компиляторами C, доступными практически для всех современных компьютерных архитектур и операционных систем. Книга «Язык программирования C» , написанная в соавторстве с разработчиком оригинального языка, в течение многих лет служила фактическим стандартом для языка. [12] [1] C был стандартизирован с 1989 года Американским национальным институтом стандартов (ANSI), а затем совместно Международной организацией по стандартизации (ISO) и Международной электротехнической комиссией (IEC).

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

С 2000 года C неизменно входит в четверку лучших языков в индексе TIOBE , который является показателем популярности языков программирования. [13]

Обзор

Деннис Ритчи (справа), изобретатель языка программирования C, с Кеном Томпсоном

C — императивный , процедурный язык в традиции ALGOL . Он имеет статическую систему типов . В C весь исполняемый код содержится в подпрограммах (также называемых «функциями», хотя и не в смысле функционального программирования ). Параметры функций передаются по значению, хотя массивы передаются как указатели , т. е. адрес первого элемента в массиве. Передача по ссылке имитируется в C путем явной передачи указателей на то, на что делается ссылка.

Исходный текст программы на языке C представляет собой код свободной формы . Точки с запятой завершают операторы , а фигурные скобки используются для группировки операторов в блоки .

Язык Си также обладает следующими характеристиками:

Хотя в языке C отсутствуют некоторые функции, имеющиеся в других языках (например, объектная ориентация и сборка мусора ), их можно реализовать или эмулировать, часто с помощью внешних библиотек (например, объектной системы GLib или сборщика мусора Boehm ).

Отношения с другими языками

Многие более поздние языки заимствовали напрямую или косвенно из C, включая C++ , C# , оболочку C Unix , D , Go , Java , JavaScript (включая транспиляторы ), Julia , Limbo , LPC , Objective-C , Perl , PHP , Python , Ruby , Rust , Swift , Verilog и SystemVerilog (языки описания оборудования). [5] Эти языки заимствовали многие из своих управляющих структур и других основных функций из C. Большинство из них также выражают очень похожий синтаксис на C, и они, как правило, объединяют узнаваемый синтаксис выражений и операторов C с базовыми системами типов, моделями данных и семантикой, которые могут радикально отличаться.

История

Ранние разработки

Происхождение C тесно связано с разработкой операционной системы Unix , изначально реализованной на языке ассемблера на PDP-7 Деннисом Ритчи и Кеном Томпсоном , включившими несколько идей коллег. В конце концов, они решили перенести операционную систему на PDP-11 . Первоначальная версия Unix для PDP-11 также была разработана на языке ассемблера. [9]

Б

Томпсон хотел язык программирования для разработки утилит для новой платформы. Сначала он пытался написать компилятор Fortran , но вскоре отказался от этой идеи. Вместо этого он создал урезанную версию недавно разработанного языка системного программирования под названием BCPL . Официальное описание BCPL в то время не было доступно, [14] и Томпсон изменил синтаксис, сделав его менее многословным и похожим на упрощенный ALGOL, известный как SMALGOL. [ 15] Томпсон назвал результат B. [9] Он описал B как «семантику BCPL с большим количеством синтаксиса SMALGOL». [15] Как и BCPL, B имел самозагружаемый компилятор для облегчения переноса на новые машины. [15] Однако в конечном итоге на B было написано мало утилит, поскольку он был слишком медленным и не мог использовать такие возможности PDP-11, как байтовая адресуемость.

Новый релиз B и первый релиз C

В 1971 году Ритчи начал улучшать B, чтобы использовать возможности более мощного PDP-11. Значительным дополнением стал символьный тип данных. Он назвал его New B (NB). [15] Томпсон начал использовать NB для написания ядра Unix , и его требования сформировали направление развития языка. [15] [16] До 1972 года в язык NB были добавлены более богатые типы: в NB были массивы intи char. Также были добавлены указатели, возможность генерировать указатели на другие типы, массивы всех типов и типы, возвращаемые из функций. Массивы внутри выражений стали указателями. Был написан новый компилятор, и язык был переименован в C. [9]

Компилятор C и некоторые утилиты, созданные с его помощью, были включены в версию 2 Unix , которая также известна как Research Unix . [17]

Переписывание структур и ядра Unix

В версии 4 Unix , выпущенной в ноябре 1973 года, ядро ​​Unix было существенно переработано на языке C. [9] К этому времени язык C приобрел некоторые мощные функции, такие как типы.struct

Препроцессор был представлен около 1973 года по настоянию Алана Снайдера, а также в знак признания полезности механизмов включения файлов, доступных в BCPL и PL/I . Его первоначальная версия обеспечивала только включенные файлы и простые замены строк: и макросы без параметров. Вскоре после этого он был расширен, в основном Майком Леском , а затем Джоном Райзером, для включения макросов с аргументами и условной компиляции . [9]#include#define

Unix был одним из первых ядер операционной системы, реализованных на языке, отличном от ассемблера . Более ранние примеры включают систему Multics (которая была написана на PL/I ) и Master Control Program (MCP) для Burroughs B5000 (которая была написана на ALGOL ) в 1961 году. Около 1977 года Ритчи и Стивен С. Джонсон внесли дополнительные изменения в язык, чтобы облегчить переносимость операционной системы Unix. Компилятор Johnson's Portable C послужил основой для нескольких реализаций C на новых платформах. [16]

Обложка книги «Язык программирования Си» , первое издание, Брайана Кернигана и Денниса Ритчи

В 1978 году Брайан Керниган и Деннис Ритчи опубликовали первое издание книги «Язык программирования Си» [18] . Известная как K&R по инициалам ее авторов, книга долгие годы служила неформальной спецификацией языка . Версия языка Си, которую она описывает, обычно называется « K&R C ». Поскольку она была выпущена в 1978 году, теперь ее также называют C78 [19] . Второе издание книги [20] охватывает более поздний стандарт ANSI C , описанный ниже.

K&R представил несколько языковых функций:

Даже после публикации стандарта ANSI 1989 года, в течение многих лет K&R C по-прежнему считался « наименьшим общим знаменателем », которым ограничивали себя программисты на C, когда требовалась максимальная переносимость, поскольку многие старые компиляторы все еще использовались, а тщательно написанный код K&R C также мог быть допустимым стандартным C.

В ранних версиях языка C только функции, возвращающие типы, отличные от , intдолжны были быть объявлены, если они использовались до определения функции; функции, используемые без предварительного объявления, как предполагалось, возвращали тип int.

Например:

long some_function (); /* Это объявление функции, поэтому компилятор может знать имя и возвращаемый тип этой функции. */ /* int */ other_function (); /* Другое объявление функции. Поскольку это ранняя версия C, здесь присутствует неявный тип 'int'. Комментарий показывает, где в более поздних версиях потребуется явный спецификатор типа 'int'. */    /* int */ called_function () /* Это определение функции, включая тело кода, следующего за { фигурными скобками }. Поскольку тип возвращаемого значения не указан, функция неявно возвращает 'int' в этой ранней версии C. */ { long test1 ; register /* int */ test2 ; /* Опять же, обратите внимание, что 'int' здесь не требуется. Спецификатор типа 'int' */ /* в комментарии будет необходим в более поздних версиях C. */ /* Ключевое слово 'register' указывает компилятору, что эта переменная должна */ /* в идеале храниться в регистре, а не в стековом фрейме. */ test1 = some_function (); if ( test1 > 1 ) test2 = 0 ; else test2 = other_function (); return test2 ; }                           

Спецификаторы типов int, которые закомментированы, могут быть опущены в K&R C, но они требуются в более поздних стандартах.

Поскольку объявления функций K&R не включали никакой информации об аргументах функций, проверки типов параметров функций не выполнялись, хотя некоторые компиляторы выдавали предупреждающее сообщение, если локальная функция вызывалась с неправильным числом аргументов или если разные вызовы внешней функции использовали разные числа или типы аргументов. Были разработаны отдельные инструменты, такие как утилита lint в Unix , которые (помимо прочего) могли проверять согласованность использования функций в нескольких исходных файлах.

В последующие годы после публикации K&R C в язык было добавлено несколько функций, поддерживаемых компиляторами от AT&T (в частности PCC [21] ) и некоторых других поставщиков. Они включали:

Большое количество расширений и отсутствие соглашения по стандартной библиотеке , а также популярность языка и тот факт, что даже компиляторы Unix не реализовали спецификацию K&R в точности, привели к необходимости стандартизации. [22]

ANSI C и ISO C

В конце 1970-х и 1980-х годах версии языка C были реализованы для самых разных мэйнфреймов , мини-компьютеров и микрокомпьютеров , включая IBM PC , поскольку его популярность начала значительно расти.

В 1983 году Американский национальный институт стандартов (ANSI) сформировал комитет X3J11 для установления стандартной спецификации языка C. X3J11 основал стандарт C на реализации Unix; однако непереносимая часть библиотеки Unix C была передана рабочей группе IEEE 1003, чтобы стать основой для стандарта POSIX 1988 года . В 1989 году стандарт C был ратифицирован как ANSI X3.159-1989 «Язык программирования C». Эту версию языка часто называют ANSI C , стандартом C или иногда C89.

В 1990 году стандарт ANSI C (с изменениями форматирования) был принят Международной организацией по стандартизации (ISO) как ISO/IEC 9899:1990, который иногда называют C90. Поэтому термины «C89» и «C90» относятся к одному и тому же языку программирования.

ANSI, как и другие национальные органы по стандартизации, больше не разрабатывает стандарт C самостоятельно, а полагается на международный стандарт C, поддерживаемый рабочей группой ISO/IEC JTC1/SC22 /WG14. Национальное принятие обновления международного стандарта обычно происходит в течение года после публикации ISO.

Одной из целей процесса стандартизации C было создание надмножества K&R C, включающего многие из впоследствии введенных неофициальных функций. Комитет по стандартам также включил несколько дополнительных функций, таких как прототипы функций (заимствованные из C++), voidуказатели, поддержка международных наборов символов и локалей , а также улучшения препроцессора. Хотя синтаксис для объявлений параметров был расширен, чтобы включить стиль, используемый в C++, интерфейс K&R по-прежнему был разрешен для совместимости с существующим исходным кодом.

C89 поддерживается текущими компиляторами C, и большая часть современного кода C основана на нем. Любая программа, написанная только на стандартном C и без каких-либо аппаратно-зависимых предположений, будет корректно работать на любой платформе с соответствующей реализацией C в пределах ее ресурсов. Без таких мер предосторожности программы могут компилироваться только на определенной платформе или с определенным компилятором, например, из-за использования нестандартных библиотек, таких как библиотеки GUI , или из-за зависимости от атрибутов компилятора или платформы, таких как точный размер типов данных и порядок байтов .

В случаях, когда код должен компилироваться либо стандартными компиляторами, либо компиляторами K&R на основе C, макрос __STDC__можно использовать для разделения кода на стандартные и K&R-разделы, чтобы предотвратить использование в компиляторе K&R на основе C функций, доступных только в стандартном C.

После процесса стандартизации ANSI/ISO спецификация языка C оставалась относительно статичной в течение нескольких лет. В 1995 году была опубликована Нормативная поправка 1 к стандарту C 1990 года (ISO/IEC 9899/AMD1:1995, неформально известная как C95), в которой были исправлены некоторые детали и добавлена ​​более обширная поддержка международных наборов символов. [23]

С99

Стандарт C был дополнительно пересмотрен в конце 1990-х годов, что привело к публикации ISO/IEC 9899:1999 в 1999 году, который обычно называют « C99 ». С тех пор он был изменен трижды Техническими исправлениями. [24]

C99 представил несколько новых функций, включая встроенные функции , несколько новых типов данных (включая long long intи complexтип для представления комплексных чисел ), массивы переменной длины и гибкие элементы массива , улучшенную поддержку плавающей точки IEEE 754 , поддержку вариативных макросов (макросов переменной арности ) и поддержку однострочных комментариев, начинающихся с //, как в BCPL или C++. Многие из них уже были реализованы как расширения в нескольких компиляторах C.

C99 по большей части обратно совместим с C90, но в некоторых отношениях строже; в частности, объявление, в котором отсутствует спецификатор типа, больше не intподразумевается. Стандартный макрос __STDC_VERSION__определяется со значением 199901L, указывающим на доступность поддержки C99. GCC , Solaris Studio и другие компиляторы C теперь [ когда? ] поддерживают многие или все новые возможности C99. Однако компилятор C в Microsoft Visual C++ реализует стандарт C89 и те части C99, которые требуются для совместимости с C++11 . [25] [ нужно обновить ]

Кроме того, стандарт C99 требует поддержки идентификаторов, использующих Unicode в виде экранированных символов (например, \u0040или \U0001f431), и предлагает поддержку необработанных имен Unicode.

С11

В 2007 году началась работа над очередной редакцией стандарта C, неофициально называемой «C1X» до ее официальной публикации ISO/IEC 9899:2011 08.12.2011. Комитет по стандартам C принял руководящие принципы, ограничивающие принятие новых функций, которые не были протестированы существующими реализациями.

Стандарт C11 добавляет многочисленные новые функции в C и библиотеку, включая макросы типов generic, анонимные структуры, улучшенную поддержку Unicode, атомарные операции, многопоточность и функции проверки границ. Он также делает некоторые части существующей библиотеки C99 необязательными и улучшает совместимость с C++. Стандартный макрос __STDC_VERSION__определен как 201112Lуказывающий на доступность поддержки C11.

С17

Опубликованный в июне 2018 года как ISO/IEC 9899:2018, C17 является текущим стандартом для языка программирования C. Он не вводит новых языковых возможностей, а только технические исправления и пояснения к дефектам в C11. Стандартный макрос __STDC_VERSION__определен как 201710Lуказывающий на доступность поддержки C17.

С23

C23 — неофициальное название следующей (после C17) крупной редакции стандарта языка C. На протяжении большей части разработки он был неофициально известен как «C2X». Ожидается, что C23 будет опубликован в начале 2024 года как ISO/IEC 9899:2024. [26] Стандартный макрос __STDC_VERSION__определен как 202311Lуказывающий на доступность поддержки C23.

C2Y

C2Y — это временное неофициальное название для следующей крупной редакции стандарта языка C после C23 (C2X), которая, как ожидается, будет выпущена позднее в десятилетии 2020-х годов, отсюда и «2» в «C2Y». Ранний рабочий проект C2Y был выпущен в феврале 2024 года как N3220 рабочей группой ISO/IEC JTC1/SC22 /WG14. [27]

Встроенный C

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

В 2008 году Комитет по стандартам C опубликовал технический отчет , расширяющий язык C [28] для решения этих проблем путем предоставления общего стандарта для всех реализаций. Он включает ряд функций, недоступных в обычном C, таких как арифметика с фиксированной точкой , именованные адресные пространства и базовая аппаратная адресация ввода-вывода.

Синтаксис

C имеет формальную грамматику, определенную стандартом C. [29] Окончания строк, как правило, не имеют значения в C; однако границы строк имеют значение на этапе предварительной обработки. Комментарии могут появляться либо между разделителями /*и */, либо (начиная с C99) после //до конца строки. Комментарии, разделенные /*и , */не вкладывают друг в друга, и эти последовательности символов не интерпретируются как разделители комментариев, если они появляются внутри строковых или символьных литералов. [30]

Исходные файлы C содержат объявления и определения функций. Определения функций, в свою очередь, содержат объявления и операторы . Объявления либо определяют новые типы с помощью таких ключевых слов, как struct, union, и enum, либо назначают типы и, возможно, резервируют хранилище для новых переменных, обычно записывая тип с последующим именем переменной. Ключевые слова, как charи , intуказывают встроенные типы. Разделы кода заключаются в фигурные скобки ( {и }, иногда называемые «фигурными скобками»), чтобы ограничить область объявлений и действовать как один оператор для управляющих структур.

Как императивный язык, C использует операторы для указания действий. Наиболее распространенным оператором является оператор выражения , состоящий из выражения для оценки, за которым следует точка с запятой; в качестве побочного эффекта оценки могут вызываться функции и переменным могут присваиваться новые значения. Для изменения обычного последовательного выполнения операторов C предоставляет несколько операторов потока управления, идентифицируемых зарезервированными ключевыми словами. Структурированное программирование поддерживается if... [ else] условным выполнением и do... while, while, и forитеративным выполнением (циклированием). forОператор имеет отдельные выражения инициализации, тестирования и повторной инициализации, любое или все из которых могут быть опущены. breakи continueможет использоваться внутри цикла. Break используется для выхода из самого внутреннего охватывающего оператора цикла, а continue используется для перехода к его повторной инициализации. Существует также неструктурированный gotoоператор, который напрямую переходит к назначенной метке внутри функции. switchвыбирает caseдля выполнения на основе значения целочисленного выражения. В отличие от многих других языков, поток управления перейдет к следующему, caseесли не будет завершен с помощью break.

Выражения могут использовать множество встроенных операторов и могут содержать вызовы функций. Порядок, в котором оцениваются аргументы функций и операнды большинства операторов, не определен. Оценки могут даже чередоваться. Однако все побочные эффекты (включая сохранение в переменных) будут иметь место до следующей « точки последовательности »; точки последовательности включают конец каждого оператора выражения, а также вход в каждый вызов функции и возврат из него. Точки последовательности также возникают во время оценки выражений, содержащих определенные операторы ( &&, ||, ?:и оператор запятая ). Это обеспечивает высокую степень оптимизации объектного кода компилятором, но требует от программистов на языке C большей осторожности для получения надежных результатов, чем это необходимо для других языков программирования.

Керниган и Ритчи говорят в «Введении в язык программирования Си» : «С, как и любой другой язык, имеет свои недостатки. Некоторые операторы имеют неправильный приоритет; некоторые части синтаксиса могли бы быть лучше». [31] Стандарт Си не пытался исправить многие из этих недостатков из-за влияния таких изменений на уже существующее программное обеспечение.

Набор символов

Базовый набор исходных символов языка C включает следующие символы:

Символ новой строки обозначает конец текстовой строки; он не обязательно должен соответствовать отдельному символу, хотя для удобства язык C рассматривает его как один символ.

Дополнительные многобайтовые кодированные символы могут использоваться в строковых литералах, но они не полностью переносимы . Последний стандарт C ( C11 ) позволяет переносимо встраивать многонациональные символы Unicode в исходный текст C с помощью кодировки \uXXXXили (где обозначает шестнадцатеричный символ), хотя эта функция пока не получила широкого распространения.\UXXXXXXXXX

Базовый набор символов выполнения C содержит те же символы, а также представления для alert , backspace и cart return . Поддержка времени выполнения для расширенных наборов символов увеличивалась с каждой редакцией стандарта C.

Зарезервированные слова

Следующие зарезервированные слова чувствительны к регистру .

C89 имеет 32 зарезервированных слова, также известных как ключевые слова, которые не могут быть использованы ни для каких целей, кроме тех, для которых они предопределены:

C99 зарезервировал еще пять слов: (‡ — альтернативный вариант написания ключевого слова C23)

C11 зарезервировал еще семь слов: [32] (‡ — альтернативный вариант написания ключевого слова C23)

C23 зарезервировал еще пятнадцать слов:

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

До C89 entryбыло зарезервировано как ключевое слово. Во втором издании своей книги «Язык программирования C» , в которой описывается то, что стало известно как C89, Керниган и Ритчи написали: «… [ключевое слово] entry, ранее зарезервированное, но никогда не использовавшееся, больше не зарезервировано». и « entryКлючевое слово «мертворожденный» отозвано». [33]

Операторы

C поддерживает богатый набор операторов , которые являются символами, используемыми в выражении для указания манипуляций, которые необходимо выполнить при оценке этого выражения. В C есть операторы для:

C использует оператор =(используемый в математике для выражения равенства) для указания присваивания, следуя прецеденту Fortran и PL/I , но в отличие от ALGOL и его производных. C использует оператор ==для проверки на равенство. Сходство между этими двумя операторами (присваивание и равенство) может привести к случайному использованию одного вместо другого, и во многих случаях ошибка не приводит к появлению сообщения об ошибке (хотя некоторые компиляторы выдают предупреждения). Например, условное выражение if (a == b + 1)может быть ошибочно записано как if (a = b + 1), что будет оценено как, trueесли только значение aне находится 0после присваивания. [34]

Приоритет оператора C не всегда интуитивно понятен. Например, оператор ==связывает более тесно (выполняется до) операторов &(побитовое И) и |(побитовое ИЛИ) в выражениях, таких как x & 1 == 0, которые должны быть написаны так, как (x and 1) == 0будто это намерение кодера. [35]

Пример "Привет, мир"

Программа «Hello, World!» Брайана Кернигана (1978)

Пример " hello, world ", который появился в первом издании K&R , стал моделью для вводной программы в большинстве учебников по программированию. Программа печатает "hello, world" на стандартный вывод , который обычно является терминалом или экраном.

Первоначальная версия была: [36]

main () { printf ( "привет, мир \n " ); } 

Соответствующая стандарту программа «Привет, мир» выглядит следующим образом: [a]

# включить <stdio.h>  int main ( void ) { printf ( "привет, мир \n " ); }  

Первая строка программы содержит директиву предварительной обработки , обозначенную как #include. Это заставляет компилятор заменить эту строку всем текстом stdio.hстандартного заголовка, который содержит объявления для стандартных функций ввода и вывода, таких как printfи scanf. Угловые скобки, окружающие его, stdio.hуказывают, что stdio.hможно найти с помощью стратегии поиска, которая отдает предпочтение заголовкам, предоставленным с компилятором, другим заголовкам с тем же именем, в отличие от двойных кавычек, которые обычно включают локальные или специфичные для проекта файлы заголовков.

mainСледующая строка указывает, что определяется функция с именем . mainФункция выполняет особую функцию в программах на языке C; среда выполнения вызывает mainфункцию, чтобы начать выполнение программы. Спецификатор типа intуказывает, что значение, возвращаемое вызывающему (в данном случае среде выполнения) в результате оценки функции main, является целым числом. Ключевое слово voidas a список параметров указывает, что эта функция не принимает аргументов. [b]

Открывающая фигурная скобка указывает на начало определения функции main.

Следующая строка вызывает (перенаправляет выполнение) функцию с именем printf, которая в этом случае предоставляется из системной библиотеки . В этом вызове printfфункции передается (предоставляется) один аргумент, адрес первого символа в строковом литерале "hello, world\n" . Строковый литерал представляет собой неименованный массив с элементами типа char, автоматически настроенный компилятором с конечным символом NULL (значение ASCII 0) для обозначения конца массива (для того, printfчтобы узнать длину строки). Символ NULL также может быть записан как escape-последовательность , записанная как \0. Это \nescape -последовательность , которую C транслирует в символ новой строки , который на выходе обозначает конец текущей строки. Возвращаемое значение функции printfимеет тип int, но оно молча отбрасывается, поскольку не используется. (Более осторожная программа могла бы проверить возвращаемое значение, чтобы определить, была ли функция printfуспешной.) Точка с запятой ;завершает оператор.

Закрывающая фигурная скобка указывает на конец кода функции main. Согласно спецификации C99 и более поздним версиям, mainфункция, в отличие от любой другой функции, неявно вернет значение 0при достижении , }которое завершает функцию. (Раньше return 0;требовалось явное выражение.) Это интерпретируется системой выполнения как код выхода, указывающий на успешное выполнение. [37]

Типы данных

Система типов в C является статической и слабо типизированной , что делает ее похожей на систему типов потомков ALGOL, таких как Pascal . [38] Существуют встроенные типы для целых чисел различных размеров, как со знаком, так и без знака, чисел с плавающей точкой и перечислимых типов ( enum). Целочисленный тип charчасто используется для однобайтовых символов. В C99 был добавлен логический тип данных . Существуют также производные типы, включая массивы , указатели , записи ( struct) и объединения ( union).

C часто используется в низкоуровневом системном программировании, где могут потребоваться выходы из системы типов. Компилятор пытается обеспечить корректность типов большинства выражений, но программист может переопределить проверки различными способами, либо используя приведение типов для явного преобразования значения из одного типа в другой, либо используя указатели или объединения для переинтерпретации базовых битов объекта данных каким-либо другим способом.

Некоторые считают синтаксис объявления языка C неинтуитивным, особенно для указателей функций . (Идея Ритчи состояла в том, чтобы объявлять идентификаторы в контекстах, напоминающих их использование: « объявление отражает использование ».) [39]

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

Указатели

C поддерживает использование указателей , типа ссылки , которая записывает адрес или местоположение объекта или функции в памяти. Указатели можно разыменовывать для доступа к данным, хранящимся по указанному адресу, или для вызова указанной функции. Указатели можно обрабатывать с помощью присваивания или арифметики указателей . Представление значения указателя во время выполнения обычно представляет собой необработанный адрес памяти (возможно, дополненный полем смещения внутри слова), но поскольку тип указателя включает тип указываемой вещи, выражения, включающие указатели, могут быть проверены на соответствие типу во время компиляции. Арифметика указателей автоматически масштабируется по размеру типа данных, на который указывает.

Указатели используются для многих целей в C. Текстовые строки обычно обрабатываются с помощью указателей в массивах символов. Динамическое выделение памяти выполняется с помощью указателей; результат a mallocобычно приводится к типу данных данных, которые должны быть сохранены. Многие типы данных, такие как деревья , обычно реализуются как динамически выделяемые structобъекты, связанные вместе с помощью указателей. Указатели на другие указатели часто используются в многомерных массивах и массивах structобъектов. Указатели на функции ( указатели функций ) полезны для передачи функций в качестве аргументов функциям более высокого порядка (таким как qsort или bsearch ), в таблицах диспетчеризации или в качестве обратных вызовов обработчикам событий . [37]

Значение указателя null явно не указывает на допустимое местоположение. Разыменование значения указателя null не определено, что часто приводит к ошибке сегментации . Значения указателя null полезны для указания особых случаев, таких как отсутствие указателя «next» в конечном узле связанного списка , или как указание на ошибку от функций, возвращающих указатели. В соответствующих контекстах в исходном коде, таких как назначение переменной указателя, константа указателя null может быть записана как 0, с явным приведением к типу указателя или без него, как NULLмакрос, определенный несколькими стандартными заголовками или, начиная с C23, с константой nullptr. В условных контекстах значения указателя null оцениваются как false, в то время как все другие значения указателей оцениваются как true.

Указатели void ( void *) указывают на объекты неопределенного типа и, следовательно, могут использоваться как «общие» указатели данных. Поскольку размер и тип указываемого объекта неизвестны, указатели void не могут быть разыменованы, и арифметика указателей на них не допускается, хотя они могут быть легко (и во многих контекстах неявно) преобразованы в любой другой тип указателя объекта и из него. [37]

Небрежное использование указателей потенциально опасно. Поскольку они обычно не проверяются, переменную-указатель можно заставить указывать на любое произвольное место, что может вызвать нежелательные эффекты. Хотя правильно используемые указатели указывают на безопасные места, их можно заставить указывать на небезопасные места, используя недопустимую арифметику указателей ; объекты, на которые они указывают, могут продолжать использоваться после освобождения ( висячие указатели ); их можно использовать без инициализации ( дикие указатели ); или им может быть напрямую присвоено небезопасное значение с помощью приведения, объединения или через другой поврежденный указатель. В целом, C допускает манипуляцию и преобразование между типами указателей, хотя компиляторы обычно предоставляют возможности для различных уровней проверки. Некоторые другие языки программирования решают эти проблемы, используя более ограничивающие ссылочные типы.

Массивы

Типы массивов в C традиционно имеют фиксированный, статический размер, указанный во время компиляции. Более поздний стандарт C99 также допускает форму массивов переменной длины. Однако также возможно выделить блок памяти (произвольного размера) во время выполнения, используя mallocфункцию стандартной библиотеки, и рассматривать его как массив.

Поскольку доступ к массивам всегда осуществляется (фактически) через указатели, доступ к массиву обычно не проверяется на соответствие базовому размеру массива, хотя некоторые компиляторы могут предоставлять проверку границ в качестве опции. [40] [41] Поэтому возможны нарушения границ массива, которые могут привести к различным последствиям, включая незаконный доступ к памяти, повреждение данных, переполнение буфера и исключения во время выполнения.

В языке C нет специального положения для объявления многомерных массивов , но вместо этого он полагается на рекурсию в системе типов для объявления массивов массивов, что фактически выполняет то же самое. Значения индекса результирующего «многомерного массива» можно рассматривать как увеличивающиеся в порядке возрастания строк . Многомерные массивы обычно используются в численных алгоритмах (в основном из прикладной линейной алгебры ) для хранения матриц. Структура массива C хорошо подходит для этой конкретной задачи. Однако в ранних версиях C границы массива должны быть известными фиксированными значениями или явно передаваться любой подпрограмме, которая их требует, а к динамическим массивам массивов нельзя получить доступ с помощью двойной индексации. (Обходным путем для этого было выделение массиву дополнительного «вектора-строки» указателей на столбцы.) В C99 были введены «массивы переменной длины», которые решают эту проблему.

Следующий пример с использованием современного языка C (C99 или более поздней версии) демонстрирует размещение двумерного массива в куче и использование индексации многомерного массива для доступа (который может использовать проверку границ во многих компиляторах C):

int func ( int N , int M ) { float ( * p )[ N ] [ M ] = malloc ( sizeof * p ); if ( p == 0 ) return -1 ; for ( int i = 0 ; i < N ; i ++ ) for ( int j = 0 ; j < M ; j ++ ) ( * p )[ i ] [ j ] = i + j ; print_array ( N , M , p ); free ( p ); return 1 ; }                                              

А вот похожая реализация с использованием функции Auto VLA C99 : [c]

int func ( int N , int M ) { // Внимание: необходимо выполнить проверки, чтобы убедиться, что N*M*sizeof(float) НЕ превышает ограничений для автоматических VLA и находится в пределах доступного размера стека. float p [ N ] [ M ]; // автоматический VLA хранится в стеке и его размер изменяется при вызове функции for ( int i = 0 ; i < N ; i ++ ) for ( int j = 0 ; j < M ; j ++ ) p [ i ] [ j ] = i + j ; print_array ( N , M , p ); // нет необходимости в free(p), так как он исчезнет при выходе из функции вместе с остальной частью стекового фрейма return 1 ; }                                       

Взаимозаменяемость массива и указателя

Индексная нотация x[i](где xобозначает указатель) является синтаксическим сахаром для *(x+i). [42] Используя знание компилятором типа указателя, адрес, который x + iуказывает на , не является базовым адресом (на который указывает x), увеличенным на iбайты, а скорее определяется как базовый адрес, увеличенный на , iумноженный на размер элемента, xна который указывает. Таким образом, x[i]обозначает i+1th-й элемент массива.

Более того, в большинстве контекстов выражений (заметным исключением является операнд sizeof), выражение типа массива автоматически преобразуется в указатель на первый элемент массива. Это подразумевает, что массив никогда не копируется целиком, когда он назван как аргумент функции, а передается только адрес его первого элемента. Поэтому, хотя вызовы функций в C используют семантику передачи по значению , массивы фактически передаются по ссылке .

Общий размер массива xможно определить, применив sizeofк выражению типа массива. Размер элемента можно определить, применив оператор sizeofк любому разыменованному элементу массива A, как в n = sizeof A[0]. Таким образом, количество элементов в объявленном массиве Aможно определить как sizeof A / sizeof A[0]. Обратите внимание, что если доступен только указатель на первый элемент, как это часто бывает в коде C из-за описанного выше автоматического преобразования, информация о полном типе массива и его длине теряется.

Управление памятью

Одной из важнейших функций языка программирования является предоставление возможностей для управления памятью и объектами, которые хранятся в памяти. C предоставляет три основных способа выделения памяти для объектов: [37]

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

Там, где это возможно, автоматическое или статическое выделение обычно является самым простым, поскольку хранилищем управляет компилятор, освобождая программиста от потенциально подверженной ошибкам рутинной работы по ручному выделению и освобождению хранилища. Однако многие структуры данных могут изменяться в размере во время выполнения, и поскольку статическое выделение (и автоматическое выделение до C99) должно иметь фиксированный размер во время компиляции, существует много ситуаций, в которых необходимо динамическое выделение. [37] До стандарта C99 распространенным примером этого были массивы переменного размера. (См. статью о mallocпримере динамически выделенных массивов.) В отличие от автоматического выделения, которое может дать сбой во время выполнения с неконтролируемыми последствиями, функции динамического выделения возвращают указание (в виде значения нулевого указателя), когда требуемое хранилище не может быть выделено. (Статическое выделение, которое слишком велико, обычно обнаруживается компоновщиком или загрузчиком , прежде чем программа сможет даже начать выполнение.)

Если не указано иное, статические объекты содержат нулевые или пустые значения указателя при запуске программы. Автоматически и динамически выделяемые объекты инициализируются только в том случае, если начальное значение указано явно; в противном случае они изначально имеют неопределенные значения (обычно это любая битовая комбинация , которая случайно присутствует в хранилище , которая может даже не представлять допустимое значение для этого типа). Если программа пытается получить доступ к неинициализированному значению, результаты не определены. Многие современные компиляторы пытаются обнаружить и предупредить об этой проблеме, но могут возникнуть как ложные срабатывания, так и ложные отрицания .

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

Библиотеки

Язык программирования C использует библиотеки в качестве основного метода расширения. В C библиотека представляет собой набор функций, содержащихся в одном файле «архива». Каждая библиотека обычно имеет заголовочный файл , который содержит прототипы функций, содержащихся в библиотеке, которые могут использоваться программой, а также объявления специальных типов данных и макросимволов, используемых с этими функциями. Чтобы программа могла использовать библиотеку, она должна включать заголовочный файл библиотеки, а библиотека должна быть связана с программой, что во многих случаях требует флагов компилятора (например, -lm, сокращение для «link the math library»). [37]

Наиболее распространенной библиотекой C является стандартная библиотека C , которая определена стандартами ISO и ANSI C и поставляется с каждой реализацией C (реализации, ориентированные на ограниченные среды, такие как встроенные системы, могут предоставлять только подмножество стандартной библиотеки). Эта библиотека поддерживает потоковый ввод и вывод, выделение памяти, математику, символьные строки и значения времени. Несколько отдельных стандартных заголовков (например, stdio.h) определяют интерфейсы для этих и других стандартных библиотечных возможностей.

Другой распространенный набор функций библиотеки C — это те, которые используются приложениями, специально предназначенными для Unix и Unix-подобных систем, особенно функции, которые предоставляют интерфейс к ядру . Эти функции подробно описаны в различных стандартах, таких как POSIX и Single UNIX Specification .

Поскольку многие программы были написаны на языке C, существует широкий спектр других доступных библиотек. Библиотеки часто пишутся на языке C, поскольку компиляторы C генерируют эффективный объектный код ; затем программисты создают интерфейсы к библиотеке, чтобы процедуры можно было использовать из языков более высокого уровня, таких как Java , Perl и Python . [37]

Обработка файлов и потоков

Файловый ввод и вывод (I/O) не является частью самого языка C, а вместо этого обрабатывается библиотеками (например, стандартной библиотекой C) и связанными с ними заголовочными файлами (например stdio.h). Обработка файлов обычно реализуется посредством высокоуровневого ввода-вывода, который работает через потоки . С этой точки зрения поток представляет собой поток данных, который не зависит от устройств, в то время как файл является конкретным устройством. Высокоуровневый ввод-вывод выполняется посредством ассоциации потока с файлом. В стандартной библиотеке C буфер ( область памяти или очередь) временно используется для хранения данных перед их отправкой в ​​конечный пункт назначения. Это сокращает время ожидания более медленных устройств, например, жесткого диска или твердотельного накопителя . Функции низкоуровневого ввода-вывода не являются частью стандартной библиотеки C [ необходимо разъяснение ], но обычно являются частью программирования «на голом железе» (программирования, которое не зависит от какой-либо операционной системы , например, большинства встроенных программ ). За некоторыми исключениями, реализации включают низкоуровневый ввод-вывод.

Языковые инструменты

Разработан ряд инструментов, помогающих программистам на языке C находить и исправлять операторы с неопределенным поведением или возможно ошибочными выражениями с большей строгостью, чем та, которую предоставляет компилятор. Инструмент lint был первым таким инструментом, за которым последовало множество других.

Автоматизированная проверка и аудит исходного кода полезны для любого языка, и для C существует множество таких инструментов, таких как Lint . Распространенной практикой является использование Lint для обнаружения сомнительного кода при первом написании программы. После того, как программа проходит Lint, она затем компилируется с помощью компилятора C. Кроме того, многие компиляторы могут опционально предупреждать о синтаксически допустимых конструкциях, которые, скорее всего, на самом деле являются ошибками. MISRA C — это фирменный набор рекомендаций по избежанию такого сомнительного кода, разработанный для встраиваемых систем. [43]

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

Такие инструменты, как Purify или Valgrind , а также связь с библиотеками, содержащими специальные версии функций выделения памяти, могут помочь обнаружить ошибки времени выполнения при использовании памяти. [44] [45]

Использует

Обоснование использования в системном программировании

Некоторое программное обеспечение, написанное на языке C

C широко используется для системного программирования при реализации операционных систем и встроенных системных приложений. [46] Это происходит по нескольким причинам:

Используется для библиотек с интенсивными вычислениями.

C позволяет программистам создавать эффективные реализации алгоритмов и структур данных, поскольку уровень абстракции от оборудования тонок, а его накладные расходы низки, что является важным критерием для программ с интенсивными вычислениями. Например, GNU Multiple Precision Arithmetic Library , GNU Scientific Library , Mathematica и MATLAB полностью или частично написаны на C. Многие языки поддерживают вызов библиотечных функций на C, например, фреймворк NumPy на основе Python использует C для аспектов высокой производительности и взаимодействия с оборудованием.

C как промежуточный язык

C иногда используется как промежуточный язык реализациями других языков. Этот подход может использоваться для переносимости или удобства; при использовании C в качестве промежуточного языка дополнительные машинно-специфичные генераторы кода не нужны. C имеет некоторые особенности, такие как директивы препроцессора номеров строк и необязательные лишние запятые в конце списков инициализаторов, которые поддерживают компиляцию сгенерированного кода. Однако некоторые из недостатков C побудили разработать другие основанные на C языки, специально разработанные для использования в качестве промежуточных языков, такие как C-- . Кроме того, современные основные компиляторы GCC и LLVM оба имеют промежуточное представление , которое не является C, и эти компиляторы поддерживают внешние интерфейсы для многих языков, включая C.

Другие языки, написанные на C

Следствием широкой доступности и эффективности языка C является то, что компиляторы , библиотеки и интерпретаторы других языков программирования часто реализуются на языке C. [47] Например, эталонные реализации Python , [48] Perl , [49] Ruby , [50] и PHP [51] написаны на языке C.

Когда-то использовался для веб-разработки

Исторически C иногда использовался для веб-разработки с использованием Common Gateway Interface (CGI) в качестве «шлюза» для информации между веб-приложением, сервером и браузером. [52] C, возможно, был выбран среди интерпретируемых языков из-за его скорости, стабильности и почти универсальной доступности. [53] Веб-разработка больше не является общепринятой практикой, [54] и существует множество других инструментов веб-разработки .

Веб-серверы

Два самых популярных веб-сервера , Apache HTTP Server и Nginx , написаны на языке C. Эти веб-серверы взаимодействуют с операционной системой, прослушивают порты TCP на предмет HTTP-запросов, а затем обслуживают статический веб-контент или вызывают выполнение других языков обработки для «рендеринга» контента, таких как PHP , который сам по себе в основном написан на языке C. Подход C, близкий к «железу», позволяет создавать эти высокопроизводительные программные системы.

Приложения для конечных пользователей

Язык C также широко использовался для реализации приложений конечного пользователя . [55] Однако такие приложения также могут быть написаны на более новых языках более высокого уровня.

Ограничения

мощь языка ассемблера и удобство ... языка ассемблера

—  Деннис Ричи [56]

Несмотря на то, что язык C популярен, влиятелен и чрезвычайно успешен, у него есть недостатки, в том числе:

Для некоторых целей были приняты ограниченные стили C, например MISRA C или CERT C , в попытке уменьшить возможность ошибок. Базы данных, такие как CWE, пытаются подсчитать, как C и т. д. имеет уязвимости, вместе с рекомендациями по смягчению.

Существуют инструменты, которые могут смягчить некоторые недостатки. Современные компиляторы C включают проверки, которые могут генерировать предупреждения, помогающие выявить множество потенциальных ошибок.

Родственные языки

График индекса TIOBE , показывающий сравнение популярности различных языков программирования [62]

Язык C оказал как прямое, так и косвенное влияние на многие более поздние языки, такие как C++ и Java . [63] Наиболее сильное влияние было синтаксическим; все упомянутые языки объединяют синтаксис операторов и (более или менее узнаваемый) выражений языка C с системами типов, моделями данных или крупномасштабными программными структурами, которые отличаются от таковых в языке C, иногда радикально.

Существует несколько интерпретаторов языка C или близких к нему языков, включая Ch и CINT , которые также можно использовать для написания скриптов.

Когда объектно-ориентированные языки программирования стали популярными, C++ и Objective-C были двумя различными расширениями C, которые предоставляли объектно-ориентированные возможности. Оба языка изначально были реализованы как компиляторы исходного кода ; исходный код был переведен в C, а затем скомпилирован с помощью компилятора C. [64]

Язык программирования C++ (первоначально называвшийся «C with Classes ») был разработан Бьярне Страуструпом как подход к предоставлению объектно-ориентированной функциональности с синтаксисом, подобным C. [65] C++ добавляет большую силу типизации, область действия и другие инструменты, полезные в объектно-ориентированном программировании, и допускает обобщенное программирование с помощью шаблонов. Почти надмножество C, C++ теперь [ когда? ] поддерживает большую часть C, за некоторыми исключениями .

Objective-C изначально был очень «тонким» слоем поверх C и остается строгим надмножеством C, которое допускает объектно-ориентированное программирование с использованием гибридной динамической/статической парадигмы типизации. Objective-C унаследовал свой синтаксис как от C, так и от Smalltalk : синтаксис, включающий предварительную обработку, выражения, объявления функций и вызовы функций, унаследован от C, в то время как синтаксис для объектно-ориентированных функций изначально был взят из Smalltalk.

Помимо C++ и Objective-C , Ch , Cilk и Unified Parallel C являются почти надмножествами C.

Смотрите также

Примечания

  1. ^ Исходный пример кода будет компилироваться на большинстве современных компиляторов, которые не находятся в режиме строгого соответствия стандарту, но он не полностью соответствует требованиям C89 или C99. Фактически, C99 требует, чтобы было создано диагностическое сообщение.
  2. ^ Функция mainна самом деле имеет два аргумента, int argcи char *argv[], соответственно, которые могут использоваться для обработки аргументов командной строки . Стандарт ISO C (раздел 5.1.2.2.1) требует mainподдержки обеих форм , что является особым режимом, не предусмотренным ни для одной другой функции.
  3. ^ Код print_array(не показан) немного отличается, [ почему? ] тоже.

Ссылки

  1. ^ ab Prinz, Peter; Crawford, Tony (16 декабря 2005 г.). C in a Nutshell. O'Reilly Media, Inc. стр. 3. ISBN 9780596550714.
  2. Ритчи (1993): «Томпсон предпринял кратковременную попытку создать систему, закодированную на ранней версии C — до структур — в 1972 году, но оставил эту попытку».
  3. ^ "N3221 – Отчет редактора, после встречи в Страсбурге, Франция, в январе 2024 г.". ISO/IEC JTC1/SC22/WG14 . Открытые стандарты. 21 февраля 2024 г. Получено 24 мая 2024 г.
  4. Ритчи (1993): «Схема композиции типов, принятая в языке Си, во многом обязана Алголу 68, хотя она, возможно, и не появилась в той форме, которую одобрили бы приверженцы Алгола».
  5. ^ ab "Verilog HDL (и C)" (PDF) . Исследовательская школа компьютерных наук Австралийского национального университета. 3 июня 2010 г. Архивировано из оригинала (PDF) 6 ноября 2013 г. . Получено 19 августа 2013 г. . 1980-е: Verilog впервые представлен; Verilog вдохновлен языком программирования C
  6. ^ "Название основано на букве C в английском алфавите и произносится как она". звук языка программирования C. Англо-китайский словарь. Архивировано из оригинала 17 ноября 2022 г. Получено 17 ноября 2022 г.
  7. ^ Муньос, Дэниел. «После всех этих лет мир по-прежнему работает на программировании на языке C | Toptal». Инженерный блог Toptal . Получено 15 июня 2024 г.
  8. ^ "C Language Drops to Lowest Popularity Rating". Developer.com . 9 августа 2016 г. Архивировано из оригинала 22 августа 2022 г. Получено 1 августа 2022 г.
  9. ^ abcdef Ричи (1993)
  10. ^ "Популярность языков программирования". 2009. Архивировано из оригинала 16 января 2009 г. Получено 16 января 2009 г.
  11. ^ "TIOBE Programming Community Index". 2009. Архивировано из оригинала 4 мая 2009 г. Получено 6 мая 2009 г.
  12. ^ Уорд, Терри А. (август 1983 г.). «Аннотированная библиография языка C по C». Байт . стр. 268. Получено 31 января 2015 г.
  13. ^ "TIOBE Index for September 2024". Архивировано из оригинала 18 сентября 2024 г. Получено 20 сентября 2024 г.
  14. ^ Ритчи, Деннис. "BCPL to B to C". Архивировано из оригинала 12 декабря 2019 г. Получено 10 сентября 2019 г.
  15. ^ abcde Дженсен, Ричард (9 декабря 2020 г.). ""A damn fool thing to do" — the origins of C". Ars Technica . Архивировано из оригинала 28 марта 2022 г. . Получено 28 марта 2022 г. .
  16. ^ ab Johnson, SC ; Ritchie, DM (1978). «Переносимость программ на языке C и система UNIX». Bell System Tech. J . 57 (6): 2021–2048. CiteSeerX 10.1.1.138.35 . doi :10.1002/j.1538-7305.1978.tb02141.x. ISSN  0005-8580. S2CID  17510065. (Примечание: PDF-файл представляет собой OCR-сканирование оригинала и содержит преобразование «IBM 370» в «IBM 310».)
  17. ^ Макилрой, MD (1987). Исследовательский ридер Unix: аннотированные выдержки из Руководства программиста, 1971–1986 (PDF) (Технический отчет). CSTR. Bell Labs. стр. 10. 139. Архивировано (PDF) из оригинала 11 ноября 2017 г. Получено 1 февраля 2015 г.
  18. ^ Керниган, Брайан В .; Ритчи, Деннис М. (февраль 1978 г.). Язык программирования C (1-е изд.). Энглвуд Клиффс, Нью-Джерси : Prentice Hall . ISBN 978-0-13-110163-0.
  19. ^ "C manual pages". FreeBSD Miscellaneous Information Manual (FreeBSD 13.0 ed.). 30 мая 2011 г. Архивировано из оригинала 21 января 2021 г. Получено 15 января 2021 г.[1] Архивировано 21 января 2021 г. на Wayback Machine
  20. ^ Керниган, Брайан В .; Ритчи, Деннис М. (март 1988 г.). Язык программирования C (2-е изд.). Энглвуд Клиффс, Нью-Джерси : Prentice Hall . ISBN 978-0-13-110362-7.
  21. ^ Страуструп, Бьярне (2002). Соперничество братьев и сестер: C и C++ (PDF) (Отчет). AT&T Labs. Архивировано (PDF) из оригинала 24 августа 2014 г. Получено 14 апреля 2014 г.
  22. ^ "Обоснование американского национального стандарта для информационных систем – Язык программирования – C". Архивировано из оригинала 17 июля 2024 г. Получено 17 июля 2024 г.
  23. ^ C Integrity. Международная организация по стандартизации. 30 марта 1995 г. Архивировано из оригинала 25 июля 2018 г. Получено 24 июля 2018 г.
  24. ^ "JTC1/SC22/WG14 – C". Домашняя страница . ISO/IEC. Архивировано из оригинала 12 февраля 2018 г. Получено 2 июня 2011 г.
  25. Эндрю Бинсток (12 октября 2011 г.). «Интервью с Гербом Саттером». Доктор Доббс . Архивировано из оригинала 2 августа 2013 г. Получено 7 сентября 2013 г.
  26. ^ "WG14-N3132: Пересмотренное расписание C23" (PDF) . open-std.org . 4 июня 2023 г. Архивировано (PDF) из оригинала 9 июня 2023 г.
  27. ^ "WG14-N3220: рабочий проект, C2y" (PDF) . open-std.org . 21 февраля 2024 г. Архивировано (PDF) из оригинала 26 февраля 2024 г.
  28. ^ "TR 18037: Embedded C" (PDF) . ISO / IEC. Архивировано (PDF) из оригинала 25 февраля 2021 г. . Получено 26 июля 2011 г. .
  29. ^ Харбисон, Сэмюэл П.; Стил, Гай Л. (2002). C: Справочное руководство (5-е изд.). Энглвуд Клиффс, Нью-Джерси : Prentice Hall . ISBN 978-0-13-089592-9.Содержит грамматику BNF для языка C.
  30. ^ Керниган и Ричи (1988), с. 192.
  31. ^ Керниган и Ричи (1978), с. 3.
  32. ^ "Проект комитета ISO/IEC 9899:201x (ISO C11)" (PDF) . Архивировано (PDF) из оригинала 22 декабря 2017 г. . Получено 16 сентября 2011 г. .
  33. ^ Керниган и Ричи (1988), стр. 192, 259.
  34. ^ "10 распространенных ошибок программирования на C++". Cs.ucr.edu. Архивировано из оригинала 21 октября 2008 г. Получено 26 июня 2009 г.
  35. ^ Шульц, Томас (2004). C и 8051 (3-е изд.). Отсего, Мичиган: PageFree Publishing Inc. стр. 20. ISBN 978-1-58961-237-2. Получено 10 февраля 2012 г. .
  36. ^ Керниган и Ричи (1978), с. 6.
  37. ^ abcdefg Клеменс, Бен (2013). 21 век С. О'Рейли Медиа . ISBN 978-1-4493-2714-9.
  38. ^ Фейер, Алан Р.; Гехани, Нараин Х. (март 1982 г.). «Сравнение языков программирования C и Pascal». ACM Computing Surveys . 14 (1): 73–92. doi :10.1145/356869.356872. S2CID  3136859.
  39. ^ Керниган и Ричи (1988), с. 122.
  40. ^ Например, gcc предоставляет _FORTIFY_SOURCE. "Функции безопасности: проверки буфера во время компиляции (FORTIFY_SOURCE)". fedoraproject.org. Архивировано из оригинала 7 января 2007 г. Получено 5 августа 2012 г.
  41. ^ Викискладе есть медиафайлы по теме , США (2016). Программирование на языке C. Бангкок, Таиланд: SE-EDUCATION PUBLIC COMPANY LIMITED. стр. 225–230. ISBN 978-616-08-2740-4.
  42. ^ Рэймонд, Эрик С. (11 октября 1996 г.). Новый словарь хакера (3-е изд.). MIT Press. стр. 432. ISBN 978-0-262-68092-9. Получено 5 августа 2012 г. .
  43. ^ "Man Page for lint (freebsd Section 1)". unix.com . 24 мая 2001 г. . Получено 15 июля 2014 г. .
  44. ^ "CS107 Valgrind Memcheck". web.stanford.edu . Получено 23 июня 2023 г. .
  45. ^ Хастингс, Рид; Джойс, Боб. «Purify: быстрое обнаружение утечек памяти и ошибок доступа» (PDF) . Pure Software Inc .: 9.
  46. ^ Дейл, Нелл Б.; Вимс, Чип (2014). Программирование и решение проблем с C++ (6-е изд.). Берлингтон, Массачусетс: Jones & Bartlett Learning. ISBN 978-1449694289. OCLC  894992484.
  47. ^ "C – мать всех языков". ICT Academy at IITK . 13 ноября 2018 г. Архивировано из оригинала 31 мая 2021 г. Получено 11 октября 2022 г.
  48. ^ "1. Расширение Python с помощью C или C++". Документация Python 3.10.7 . Архивировано из оригинала 5 ноября 2012 г. Получено 11 октября 2022 г.
  49. ^ Конрад, Майкл (22 января 2018 г.). «Обзор движка Perl 5». Opensource.com . Архивировано из оригинала 26 мая 2022 г. . Получено 11 октября 2022 г. .
  50. ^ "To Ruby From C and C++". Язык программирования Ruby . Архивировано из оригинала 12 августа 2013 г. Получено 11 октября 2022 г.
  51. ^ Para, Michael (3 августа 2022 г.). «Что такое PHP? Как написать свою первую программу на PHP». freeCodeCamp . Архивировано из оригинала 4 августа 2022 г. . Получено 11 октября 2022 г. .
  52. Справочник доктора Добба . США: Miller Freeman, Inc. Ноябрь–декабрь 1995 г.
  53. ^ "Использование C для программирования CGI". linuxjournal.com. 1 марта 2005 г. Архивировано из оригинала 13 февраля 2010 г. Получено 4 января 2010 г.
  54. ^ Перкинс, Люк (17 сентября 2013 г.). «Веб-разработка на языке C: безумие? Или безумие как лиса?». Medium . Архивировано из оригинала 4 октября 2014 г. Получено 8 апреля 2022 г.
  55. ^ Муньос, Дэниел. «После всех этих лет мир по-прежнему работает на программировании на языке C». Toptal Engineering Blog . Получено 17 ноября 2023 г.
  56. ^ Метц, Кейд. «Деннис Ричи: плечи, на которых стоял Стив Джобс». Wired . Архивировано из оригинала 12 апреля 2022 г. Получено 19 апреля 2022 г.
  57. ^ corob-msft (31 марта 2022 г.). "Директивы Pragma и ключевые слова __pragma и _Pragma". Microsoft Learn . Архивировано из оригинала 24 сентября 2022 г. Получено 24 сентября 2022 г.
  58. ^ "Pragmas (The C Preprocessor)". GCC, коллекция компиляторов GNU . Архивировано из оригинала 17 июня 2002 г. Получено 24 сентября 2022 г.
  59. ^ "Pragmas". Intel C++ Compiler Classic Developer Guide and Reference . Intel. Архивировано из оригинала 10 апреля 2022 г. Получено 10 апреля 2022 г.
  60. ^ «В похвалу препроцессору C». apenwarr . 13 августа 2007 г. Получено 9 июля 2023 г.
  61. ^ Робертс, Эрик С. (21 марта 1989 г.). «Реализация исключений в C» (PDF) . Исследовательский центр DEC Systems . SRC-RR-40. Архивировано (PDF) из оригинала 15 января 2017 г. . Получено 4 января 2022 г. .
  62. Макмиллан, Роберт (1 августа 2013 г.). «Java теряет свою силу?». Wired . Архивировано из оригинала 15 февраля 2017 г. Получено 5 марта 2017 г.
  63. ^ О'Реган, Джерард (24 сентября 2015 г.). Столпы вычислений: сборник избранных, основных технологических фирм . Springer. ISBN 978-3319214641. OCLC  922324121.
  64. ^ Раухвергер, Лоуренс (2004). Языки и компиляторы для параллельных вычислений: 16-й международный семинар, LCPC 2003, Колледж-Стейшн, Техас, США, 2–4 октября 2003 г.: пересмотренные статьи . Springer. ISBN 978-3540246442. OCLC  57965544.
  65. ^ Страуструп, Бьярне (1993). "История C++: 1979–1991" (PDF) . Архивировано (PDF) из оригинала 2 февраля 2019 г. . Получено 9 июня 2011 г. .

Источники

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

Внешние ссылки