Биографии Характеристики Анализ

История языка си.

Язык программирования C++

Последнее обновление: 28.08.2017

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

Своими корнями он уходит в язык Си, который был разработан в 1969-1973 годах в компании Bell Labs программистом Деннисом Ритчи (Dennis Ritchie). В начале 1980-х годов датский программист Бьерн Страуструп (Bjarne Stroustrup), который в то время работал в компании Bell Labs, разработал С++ как расширение к языку Си. Фактически вначале C++ просто дополнял язык Си некоторыми возможностями объектно-ориентированного программирования. И поэтому сам Страуструп вначале называл его как "C with classes" ("Си с классами").

Впоследствии новый язык стал набирать популярность. В него были добавлены новые возможности, которые делали его не просто дополнением к Си, а совершенно новым языком программирования. В итоге "Си с классами" был переименован в С++. И с тех по оба языка стали развиваться независимо друг от друга.

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

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

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

Основные этапы развития

В 1979-80 годах Бьерн Страуструп разработал расширение к языку Си - "Си с классами". В 1983 язык был переименован в С++.

В 1985 году была выпущена первая коммерческая версия языка С++, а также первое издание книги "Языка программирования C++", которая представляла первое описание этого языка при отсутствии официального стандарта.

В 1989 была выпущена новая версия языка C++ 2.0, которая включала ряд новых возможностей. После этого язык развивался относительно медленно вплоть до 2011 года. Но при этом в 1998 году была предпринята первая попытка по стандартизации языка организацией ISO (International Organiztion for Standartization). Первый стандарт получил название ISO/IEC 14882:1998 или сокращенно С++98. В дальнейшем в 2003 была издана новая версия стандарта C++03.

В 2011 году был издан новый стандарт C++11, который содержал множество добавлений и обогащал язык С++ большим числом новых функциональных возможностей. После этого в 2014 году было выпущено небольшое добавление к стандарту, известное также как C++14. И еще один ключевой релиз языка намечен на 2017.

Компиляторы и среды разработки

Для разработки программ на С++ необходим компилятор - он транслирует исходный код на языке С++ в исполняемый файл, который затем можно запускать. Но в настоящий момент есть очень много различных компиляторов. Они могут отличаться по различным аспектам, в частности, по реализации стандартов. Базовый список компиляторов для С++ можно посмотреть в википедии . Рекомендуется для разработки выбирать те компиляторы, которые развиваются и реализуют все последние стандарты. Так, на протяжении всего руководства преимущественно будет использоваться свободно распространяемый компилятор g++ , разработанный в рамках проекта GNU.

Также для создания программ можно использовать интегрированные среды разработки IDE, такие как Visual Studio, Netbeans, Eclipse, Qt и т.д.

Благодаря чему сложился такой статус языка С? Исторически этот язык неотделим от операционной системы Unix, которая в наши дни переживает свое второе рождение. 60-е годы были эпохой становления операционных систем и языков программирования высокого уровня. В тот период для каждого типа компьютеров независимо разрабатывались ОС и компиляторы, а нередко даже свои языки программирования (вспомним, например, PL/I). В то же время, общность возникающих при этом проблем уже стала очевидной. Ответом на осознание этой общности стала попытка создать универсальную мобильную операционную систему, а для этого понадобился не менее универсальный и мобильный язык программирования. Таким языком стал С, а Unix стала первой ОС, практически полностью написанной на языке высокого уровня.

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

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

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

Много споров вызывал синтаксис языка С. Примененные в нем приемы сокращения записи при неумеренном использовании могут сделать программу совершенно нечитаемой. Но, как говорил Дейкстра, - средства не виноваты в том, что их безграмотно используют. На самом же деле, предложенные в С сокращения синтаксиса соответствуют наиболее часто встречающимся на практике стереотипным ситуациям. Если считать сокращения идиомами для выразительного и компактного представления таких ситуаций, то польза от них становится безусловной и очевидной.

Итак, С возник как универсальный язык системного программирования. Но он не остался в этих рамках. К концу 80-х годов язык С, оттеснив Fortran с позиции лидера, завоевал массовую популярность среди программистов во всем мире и стал использоваться в самых различных прикладных задачах. Немалую роль здесь сыграло распространение Unix (а значит и С) в университетской среде, где проходило подготовку новое поколение программистов.

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

Но если все так безоблачно, то почему же еще продолжают использоваться все остальные языки, что поддерживает их существование? Ахиллесовой пятой языка С стало то, что он оказался слишком низкоуровневым для тех задач, которые поставили на повестку дня 90-е годы. Причем у этой проблемы есть два аспекта. С одной стороны, в язык были встроены слишком низкоуровневые средства - прежде всего это работа с памятью и адресная арифметика. Недаром смена разрядности процессоров очень болезненно отражается на многих С-программах. С другой стороны, в С недостает средств высокоуровневых - абстрактных типов данных и объектов, полиморфизма, обработки исключений. Как следствие, в программах на С техника реализации задачи часто доминирует над ее содержательной стороной.

Первые попытки исправить эти недостатки стали предприниматься еще в начале 80-х годов. Уже тогда Бьерн Страуструп в AT&T Bell Labs стал разрабатывать расширение языка С под условным названием. Стиль ведения разработки вполне соответствовал духу, в котором создавался и сам язык С, - в него вводились те или иные возможности с целью сделать более удобной работу конкретных людей и групп. Первый коммерческий транслятор нового языка, получившего название C++ появился в 1983 году. Он представлял собой препроцессор, транслировавший программу в код на С. Однако фактическим рождением языка можно считать выход в 1985 году книги Страуструпа. Именно с этого момента C++ начинает набирать всемирную популярность.

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

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

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

Все это привело к тому, что многие разработчики вынуждены были сами исследовать лабиринты языковой семантики и самостоятельно отыскивать успешно работающие идиомы. Так, например, на первом этапе развития языка многие создатели библиотек классов стремились построить единую иерархию классов с общим базовым классом Object. Эта идея была заимствована из Smalltalk - одного из наиболее известных объектно-ориентированных языков. Однако она оказалась совершенно нежизнеспособной в C++ - тщательно продуманные иерархии библиотек классов оказывались негибкими, а работа классов - неочевидной. Для того чтобы библиотеками классов можно было пользоваться, их приходилось поставлять в исходных текстах.

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

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

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

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

В свете всего сказанного перспективы C++ не выглядят мрачными. Хотя и монополия на рынке языков программирования ему не светит. Пожалуй, с уверенностью можно утверждать только то, что еще одной модернизации-расширения этот язык не переживет. Недаром, когда появилась Java, на нее обратили столь пристальное внимание. Язык, близкий по синтаксису к C++, а значит, кажущийся знакомым многим программистам, был избавлен от наиболее вопиющих недостатков C++, унаследованных им из 70-х годов. Однако не похоже, чтобы Java справлялась с возлагаемой на нее некоторыми ролью.

Особая роль языков C/C++ в современном программировании практически лишает смысла приведение конкретных адресов в Интернете, где можно найти материалы по ним. Таких мест просто слишком много. Однако, если интересно подробнее познакомиться с эволюцией C++, то начните с небольшой статьи http://citforum.syzran.ru/programming/prg96/76.shtml .

Александр Сергеев, [email protected]
Статья из журнала BYTE/Россия, Март 2000

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

Листинг 1. С

1 #include /* Подключаем функции ввода-вывода */ 2 3 void main(void) 4 { 5 int М; /* Массив из 10 целых, счет с 0 */ 6 int N; 7 for (N=0; N<10; ++N) /* Вводим не более 10 чисел */ 8 if (EOF == scanf ("%d, M+N)) 9 break; /* Если конец файла, прерываем цикл */ 10 11 for (-N; N>=0; --N) /* Проходим массив в обратном */ 12 if (M[N]%2) /* порядке и выводим нечетные */ 13 printf("%d\n", M[N]); 14 }

  • Строка 3. В C/C++ выполнение программы всегда начинается с функции main.
  • Строки 7 и 11. В заголовке цикла через точку с запятой указываются начальная установка, условие продолжения и правило пересчета параметра цикла. Операции ++ и -/- - известнейшие из сокращений языка С, означающие инкремент и декремент переменной, то есть увеличение и уменьшение ее значения на единицу.
  • Строка 8. Функция scanf вводит по формату, заданному первым параметром, значения переменных, адреса которых заданы остальными параметрами. Здесь адрес, куда вводится значение, вычисляется с помощью адресной арифметики, к адресу расположения массива М прибавляется смещение на N элементов. Тот же эффект можно получить, записав &M[N] .
  • Строка 12. Операция % вычисляет остаток от деления. Условие оператора if считается выполненным, если численное значение выражения отлично от нуля.
  • Строка 13. Функция printf - печать по формату действует аналогично scanf , но вместо адресов ей передаются значения, подлежащие выводу.
1 #include 2 3 template class Array 4 { 5 public: Array (T Size=1) : M (new T), N(Size), n(0) {} 6 Array (void) { delete М;} 7 T Count (void) const { return n; } 8 T operator (int i) const { return M[i]; } 9 void Add (Т Data); 10 private: 11 T* М; // Адрес распределенной памяти 12 int N, n; // N - распределено; n - использовано 13 }; 14 15 template void Array::Add(T Data) 16 { if (N-n) // Если использовано все распределенное 17 { int* P = new T; // место, распределим побольше 18 for (int i=0; i A; // Массив целых переменного размера 28 while (1) // Бесконечный цикл 29 { int N; 30 cin >> N; // cin - стандартный поток ввода 31 if (cin.eof()) break; // Выход из цикла по концу файла 32 A.Add(N); // Добавляем введенное число в массив 33 } 34 for (int N=A.Count()-1; N>=0; --N) // Проходим по массиву 35 if (A[N]%2) 36 cout <, и освободит память
  • Строки 3-13. Объявляется темплетный класс Аrray с параметром Т . Он представляет собой массив переменного размера объектов типа Т . Конечно, в нашей задаче нет никакой необходимости использовать темплетный класс. Однако нам хотелось продемонстрировать, как на C++ создается полиморфная структура данных, способная работать с любым типом элементов.
  • Строка 5. Конструктор класса. В нем инициализируется представление объекта. Например, в поле М заносится адрес блока памяти, заказанного операцией new T .
  • Строка 8. Пример перегрузки операции . Функция operator будет вызываться, когда квадратные скобки будут появляться справа от объекта класса Array .
  • Строка 9. Эта функция основная в реализации. Она добавляет элементы в массив, расширяя его при необходимости. Поскольку она сложнее остальных, ее определение вынесено из описания класса. Функции, описанные в теле класса, реализуются в C++ не вызовом, а inline-подстановкой. Это ускоряет работу программы, хотя увеличивает ее размер.
  • Строки 15-24. Определение функции Аrrау::Add(T) (между прочим, это ее полное имя).
  • Строка 27. Создаем объект типа Array . Темплет Аггау параметризируется типом int .

Язык С (читается "Си") создан в начале 70х годов, когда Кен Томпсон и Дэннис Ритчи из Bell Labs разрабатывали операционную систему UNDC. Сначала они создали часть компилятора С, затем использовали ее для компиляции остальной части компилятора С и, наконец, применили полученный в результате компилятор для компиляции UNIX. Операционная система UNIX первоначально распространялась в исходных кодах на С среди университетов и лабораторий, а получатель мог откомпилировать исходный код на С в машинный код с помощью подходящего компилятора С .

Распространение исходного кода сделало операционную систему UNIX уникальной; программист мог изменить операционную систему, а исходный код мог быть перенесен с одной аппаратной платформы на другую. Сегодня стандарт POSIX определяет стандартный набор системных вызовов UNIX, доступных в С , которые должны быть реализованы в версиях UNIX, являющихся POSIX-совместимыми. С был третьим языком, который разработали Томсон и Ритчи в процессе создания UNIX; первыми двумя были, разумеется, А и В .

По сравнению с более ранним языком - BCPL, С был улучшен путем добавления типов данных определенной длины. Например, тип данных int мог применяться для создания переменной с определенным числом битов (обычно 16), в то время как тип данных long мог использоваться для создания целой переменной с большим числом битов (обычно 32). В отличие от других языков высокого уровня, С мог работать с адресами памяти напрямую с помощью указателей и ссылок. Поскольку С сохранил способность прямого доступа к аппаратному обеспечению, его часто относят к языкам среднего уровня или в шутку называют "мобильным языком ассемблера".

Что касается грамматики и синтаксиса, то С является структурным языком программирования. В то время как многие современные программисты мыслят в категориях классов и объектов, программисты на С думают в категориях процедур и функций. В С можно определить собственные абстрактные типы данных, используя ключевое слово struct . Аналогично можно описывать собственные целые типы (перечисления) и давать другие названия существующим типам данных при помощи ключевого слова typedef . В этом смысле С является структурным языком с зародышами объектно-ориентированного программирования.

Широкое распространение языка C на различных типах компьютеров (иногда называемых аппаратными платформами) привело, к сожалению, ко многим вариациям языка. Они были похожи, но несовместимы друг с другом. Это было серьезной проблемой для разработчиков программ, нуждавшихся в написании совместимых программ, которые можно было бы выполнять на нескольких платформах. Стало ясно, что необходима стандартная версия C . В 1983г. ANSI (Американский Национальный Комитет Стандартов) сформировал технический комитет X3J11 для создания стандарта языка C (чтобы "обеспечить недвусмысленное и машинно-независимое определение языка"). В 1989 стандарт был утвержден. ANSI скооперировался с ISO (Международной Организацией Стандартов), чтобы стандартизовать C в международном масштабе; совместный стандарт был опубликован в 1990 году и назван ANSI/ISO 9899:1990. Этот стандарт совершенствуется до сих пор и поддерживается большинством фирм разработчиков компиляторов.

Бьерн Страуструп высвободил объектно-ориентированный потенциал С путем перенесения возможностей классов Simula 67 в С . Первоначально новый язык носил имя "С с классами" и только потом стал называться C++ . Язык C++ достиг популярности, будучи разработанным в Bell Labs, позже он был перенесен в другие индустрии и корпорации. Сегодня это один из наиболее популярных языков программирования в мире. C++ наследует как хорошие, так и плохие стороны С .

Бьерн Страуструп : "Я придумал C++, записал его первоначальное определение и выполнил первую реализацию. Я выбрал и сформулировал критерии проектирования C++ , разработал его основные возможности и отвечал за судьбу предложений по расширению языка в комитете по стандартизации C++ ", - пишет автор самого популярного языка программирования. - "Язык C++ многим обязан языку C , и язык C остается подмножеством языка C++ (но в C++ устранены несколько серьезных брешей системы типов C). Я также сохранил средства C , которые являются достаточно низкоуровневыми, чтобы справляться с самыми критическими системными задачами. Язык C , в свою очередь многим обязан своему предшественнику, BCPL; кстати, стиль комментариев // был взят в C++ из BCPL. Другим основным источником вдохновения был язык Simula67. Концепция классов (с производными классами и виртуальными функциями) была позаимствована из него. Средства перегрузки операторов и возможность помещения объявлений в любом месте, где может быть записана инструкция, напоминает Algol68. "

Название C++ выдумал Рик Масситти. Название указывает на эволюционную природу перехода к нему от C. "++" - это операция приращения в C. Чуть более короткое имя C+ является синтаксической ошибкой; кроме того, оно уже было использовано как имя совсем другого языка. Знатоки семантики C находят, что C++ хуже, чем ++C. Названия D язык не получил, поскольку он является расширением C и в нем не делается попыток исцеляться от проблем путем выбрасывания различных особенностей...

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

В языке С++ полностью поддерживаются принципы объектно-ориентированного программирования, включая три кита, на которых оно стоит: инкапсуляцию, наследование и полиморфизм. Инкапсуляция в С++ поддерживается посредством создания нестандартных (пользовательских) типов данных, называемых классами. Язык С++ поддерживает наследование. Это значит, что можно объявить новый тип данных (класс), который является расширением существующего.

Хотя язык программирования С++ справедливо называют продолжением С и любая работоспособная программа на языке С будет поддерживаться компилятором С++ , при переходе от С к С++ был сделан весьма существенный скачок. Язык С++ выигрывал от своего родства с языком С в течение многих лет, поскольку многие программисты обнаружили, что для того, чтобы в полной мере воспользоваться преимуществами языка С++ , им нужно отказаться от некоторых своих прежних знаний и приобрести новые, а именно: изучить новый способ концептуальности и решения проблем программирования. Перед тем как начинать осваивать С++ , Страуструп и большинство других программистов, использующих С++ считают изучение языка С необязательным.

Язык программирования C++ в настоящее время считается господствующим языком, используемым для разработки коммерческих продуктов, 90% игр пишутся на С++ с прменением DirectX.

Литература:
Х.М.Дейтел, П.Дж.Дейтел "Как программировать на C++"
Бьерн Страуструп "Язык программирования C++. 3-е издание."
Симон Робинсон, Олли Корнес, Джей Глинн и др. "C# для профессионалов"
Джесс Либерти "Освой самостоятельно С++ за 21 день"
Станислав Горнаков "DirectX, уроки программирования на С++"

Несколько ссылок и цитат про первые компиляторы C, B, BCPL, AED-0, Bootstrap Compiler; и о том, как компилировался первый компилятор новых языков



История компилятора BCPL и AED-0

BCPL was designed by Martin Richards in the mid-1960s while he was visiting MIT, and was used during the early 1970s for several interesting projects, among them the OS6 operating system at Oxford , and parts of the seminal Alto work at Xerox PARC . We became familiar with it because the MIT CTSS system on which Richards worked was used for Multics development. The original BCPL compiler was transported both to Multics and to the GE-635 GECOS system by Rudd Canaday and others at Bell Labs ; during the final throes of Multics"s life at Bell Labs and immediately after, it was the language of choice among the group of people who would later become involved with Unix.

BCPL was intended to be portable. Portability is achieved by bootstrapping the runtime system a number of times so that it eventually implements the compliler"s output language. This language is called OCODE. OCODE is similar to a high-level assembly language… also defined in such a way that it could be translated into the machine language of most processors.…
In the book on BCPL , Richards and Whitby-Strevens define a second low-level intermediate language called Intcode. Intcode is an extremely simple language that can be used to bootstrap OCODE.… The BCPL system was distributed in OCODE form.

Таким образом, для запуска компилятора BCPL, который распространялся в кодах OCODE и компилировал программы с BCPL в OCODE, требовался транслятор OCODE. Транслятор OCODE написан на Intcode, а Intcode уже достаточно прост для реализации без языков высокого уровня (единицы дней для ассемблера и интерпретатора Intcode на новой машине; хотя реализация Intcode на самом BCPL тоже возможна). Осталось лишь скомпилировать первый компилятор BCPL, написанный на BCPL в OCODE https://www.bell-labs.com/usr/dmr/www/bcpl.html :


Richards"s first BCPL compiler was written using the 6-bit BCD character set on CTSS, and adapted shortly thereafter to use the characters available on the IBM "golf-ball" 1050 and 2741 terminals.

BCPLCTSS contains the version of the BCPL compiler as it was in June 1968 running on CTSS at MIT"s Project MAC. It also contains a modification of this compiler that runs under the current 64-bit Cintcode BCPL System. Click BCPLCTSS.html to obtain a copy.
I have typed in the source code from IBM golf ball listing of the compiler dating back to between February and June 1968.

BCPL was initially similar to this subset of CPL used in the encoding of the CPL compiler. An outline of BCPL’s main features first appeared in my PhD thesis in 1966 but it was not fully designed and implemented until early the following year when I was working at Project MAC of the Massachussetts Institute of Technology. Its first implementation was written in Ross’s Algol Extended for Design (AED-0) which was the only language then available on CTSS, the time sharing system at Project MAC, other than LISP that allowed recursion.

Немного истории AED-0 есть на странице http://groups.csail.mit.edu/mac/projects/studentaut/DR%20HK%20Bio.htm и Compiler Construction. LNCS 21, isbn 3662215497 page 470 (1974) - компилятор AED-0 был переписан на язык AED-0 лишь к концу 1964 года, а в 1963 году заработал изначальный компилятор AED-0 для IBM 7094 (фото), написанный на неуточненном "bootstrap compiler language"


He started programming in July 1952 on the MIT Whirlwind computer and later, through collaboration of his MIT Computer-Aided Design Project with MIT’s Project Mac, on the pioneering Compatible Time-Sharing System (CTSS).… 1962 - 1969: MIT Computer-Aided Design Project (with Project MAC), first software engineering language (AED, Algol Extended for Design)

AED-0 is a high level language developed by the M.I.T. Computer-Aided Design Project. It is based on ALGOL60 and is aimed at providing a convinient and effective language for creating specialized computer aided design systems for a wide variety of application areas. The original AED-0 compiler written in a bootstrap compiler language became operational on an IBM 709 machine in 1963. Subsequently, it was moved to CTSS of M.I.T. Project MAC operating on an IBM 7094. Further developments were made in this system to produce a fairly stable language by late 1964. By this time, the compiler existed in its own language and all further system changes and improvements were carrier out in AED-0 itself.


… Part 1 of the manual describes the AED-0 language proper, including descriptions of several subroutine packages which extend the features of the language beyond the forms derived from Algol-60 syntax.

Идеи, которые привели к созданию AED описываются Ross в Richard L. Wexelblat. History of Programming Languages. Chapter VI APT Session. "Origins of the apt language for automatically programmed tools", 1978


Немного об AED-0 есть в отчете Project MAC "VERBAL AND GRAPHICAL LANGUAGE FOR THE AED SYSTEMI A PROGRESS REPORT" MAC-TR-4
http://publications.csail.mit.edu/lcs/pubs/pdf/MIT-LCS-TR-004.pdf#page=8


THE AED-0 COMPILER
It was found that no existing compiler could provide an efficient mechanization of the plex concept so that in the Spring of 1963 the Project undertook to construct a compiler incorporating the techniques proposed for the Computer-Aided Design System itself as the first major step toward accomplishing the goals of the Project. Prior to that time plex programming had been carried out using an experimental compiler called the Bootstrap Compiler, which also was written by the Project, both for educational experience and as an experimental tool. The AED-0 Compiler was originally written in the Bootstrap Compiler language, but recently the resulting system has been disassembled from binary machine code back into FAP assembly language and a great many changes and improvements to the AED-0 Compiler have been made so that now it is available as a public command in the Project MAC Time-Sharing System. AED-0 language at present consists of Algol-60, with some features omitted, and others for plex programming added. The compiler is very efficient and flexible and compiles very good machine code in most cases. The compiler is based directly on the plex concepts described 1 above.

По языку Bootstrap Compiler информации еще меньше, чем по AED-0. Есть отдельные упоминания в http://www.dtic.mil/dtic/tr/fulltext/u2/681342.pdf Project MAC Progress Report IV (July 1966 to July 1967) и интервью Росса
http://conservancy.umn.edu/bitstream/handle/11299/107611/oh178dtr.pdf?sequence=1 An Interview with DOUGLAS T. ROSS, 1989:


… AED releases, and also from the beginning, AED was a machine independent software engineering job. In fact, we started out in parallel on the 709 and the TX-0, before MAC was even thought of, you see. That was actually the Bootstrap Compiler--in which we first wrote AED . Then it was that first AED Compiler that we had up and running here within two weeks of Project MAC opening its doors.…
I backed out of the theoretically-beautiful and clean way that we originally were generating AED code and had the whole compiler back-end redone. We did what we called a disassembly. We took the machine code of the compiler, itself, (just a bit- map of memory essentially) and went back as though it had been written in the FAP assembly language, then came back out and reassembled the whole thing so that it would be easier to do patches. Then we changed the whole code-generation part of the compiler to generate the standard (what was called the BBS format of machine-language representation, so that whatever came out of our compiler would fit into the standards that they"d adopted for Project MAC.

Не все компиляторы начинались с компиляторов:
http://en.wikipedia.org/wiki/History_of_compiler_construction#First_compilers
http://en.wikipedia.org/wiki/Bootstrapping_(compilers%29


The first compiler was written by Grace Hopper, in 1952, for the A-0 System language. The term compiler was coined by Hopper. The A-0 functioned more as a loader or linker than the modern notion of a compiler. The first autocode and its compiler were developed by Alick Glennie in 1952 for the Mark 1 computer at the University of Manchester and is considered by some to be the first compiled programming language. The FORTRAN team led by John W. Backus at IBM is generally credited as having introduced the first complete compiler, in 1957. The first FORTRAN compiler took 18 person-years to create.
The first ALGOL 58 compiler was completed by the end of 1958 by Friedrich L. Bauer, Hermann Bottenbruch, Heinz Rutishauser, and Klaus Samelson for the Z22 computer. Bauer et al. had been working on compiler technology for the Sequentielle Formelubersetzung (i.e. sequential formula translation) in the previous years.…
The COBOL compiler for the UNIVAC II was probably the first to be written in a high-level language, namely FLOW-MATIC, by a team led by Grace Hopper.

И чуть ниже там же - пример компилятора языка, написанного на этом же языке и запускаемого на интерпретаторе языка:


Building a self-hosting compiler is a bootstrapping problem, i.e. the first such compiler for a language must be either hand written machine code or compiled by a compiler written in another language, or compiled by running the compiler in an interpreter.…
Another early self-hosting compiler was written for Lisp by Tim Hart and Mike Levin at MIT in 1962. They wrote a Lisp compiler in Lisp, testing it inside an existing Lisp interpreter. Once they had improved the compiler to the point where it could compile its own source code, it was self-hosting.…
Forth is an example of a self-hosting compiler. The self compilation and cross compilation features of Forth are commonly confused with metacompilation and metacompilers.

Популярность языка программирования Си трудно переоценить, особенно вспоминая его былые заслуги. Наверное, каждый разработчик, как минимум, знает о его существовании, и, как максимум, пробовал на нем программировать. Си является предшественником таких языков, как C++, Objective-C, C#, Java.

Компания Microsoft для разработки родного языка к своей платформе.Net выбрала именно Си-подобный синтаксис. Более того, на Си написано множество операционных систем.

Конечно, Си не идеален: создатели языка – Кен Томпсон и Деннис Ритчи – долгое время дорабатывали его. Стандартизация Си продолжается до сих пор. Он существует более 45 лет и активно используется.

С ним часто ассоциируют не один, а два языка программирования - C/C++. Однако ниже речь пойдет именно о «чистом» Си.

Язык Си восходит корнями к языку ALGOL (расшифровывается как ALGorithmic Language), который был создан в 1958 году совместно с комитетом Европейских и Американских учёных в сфере компьютерных наук на встрече в Швейцарской высшей технической школе Цюриха. Язык был ответом на некоторые недостатки языка FORTRAN и попыткой их исправить. Кроме того, разработка Си тесно связана с созданием операционной системы UNIX, над которой также работали Кен Томпсон и Деннис Ритчи.

UNIX

Проект МАС (Multiple Access Computer, Machine-Aided Cognition, Man and Computer) начался как чисто исследовательский в MIT в 1963 году.

В рамках проекта МАС была разработана операционная система CTSS (Compatible Time-Sharing System). Во второй половине 60-х было создано несколько других систем с разделением времени, например, BBN, DTSS, JOSS, SDC и Multiplexed Information and Computing Service (MULTICS) в том числе.

Multics – совместная разработка MIT, Bell Telephone Laboratories (BTL) и General Electric (GE) по созданию ОС с разделением времени для компьютера GE-645. Последний компьютер под управлением Multics выключили 31 октября 2000 года.

Однако BTL отошел от этого проекта еще в начале 1969 года.

Некоторые его сотрудники (Кен Томпсон, Деннис Ритчи, Стью Фельдман, Дуг МакИлрой, Боб Моррис, Джо Оссанна) захотели продолжить работу самостоятельно. Томпсон работал над игрой Space Travel на GE-635. Ее написали сначала для Multics, а потом переписали на Фортране под GECOS на GE-635. Игра моделировала тела Солнечной системы, а игроку надо было посадить корабль куда-нибудь на планету или спутник.

Ни софт, ни железо этого компьютера не годились для такой игры. Томпсон искал альтернативу, и переписал игру под бесхозный PDP-7. Память была объемом 8К 18-битных слов, и еще был процессор векторного дисплея для вывода красивой для того времени графики.


Изображение с сайта slideshare.net

Томпсон и Ритчи полностью вели разработку на кросс-ассемблере на GE и переносили код на перфолентах. Томпсону это активно не нравилось, и он начал писать ОС для PDP-7, начиная с файловой системы. Так появилась UNIX.

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

PDP-7 UNIX также положил начало высокоуровневому языку B, который создавался под влиянием языка BCPL. Деннис Ритчи сказал, что В - это Си без типов. BCPL помещался в 8 Кб памяти и был тщательно переработан Томпсоном. В постепенно вырос в С.


Изображение с сайта it-world.com

К 1973 году язык Си стал достаточно силён, и большая часть ядра UNIX, первоначально написанная на ассемблере PDP-11/20, была переписана на Си. Это было одно из самых первых ядер операционных систем, написанное на языке, отличном от ассемблера.

Получается, что Си – это «сопутствующий продукт», полученный во время создания операционной системы UNIX.

Прародители Си

Вдохновлённые языком ALGOL-60, Математическая лаборатория Кембриджского Университета совместно с Компьютерным отделом Лондонского университета создали в 1963 году язык CPL (Combined Programming Language).

Язык CPL посчитали сложным, и в ответ на это Мартином Ричардсоном был создан в 1966 году язык BCPL, основное предназначение которого заключалось в написании компиляторов. Сейчас он практически не используется, но в своё время из-за хорошей портируемости он играл важную роль.

BCPL использовался в начале 1970-х в нескольких интересных проектах, в числе которых - операционная система OS6 и частично в зарождающихся разработках Xerox PARC.

BCPL послужил предком для языка Би (B), разработанного в 1969 в уже знакомой всем AT&T Bell Telephone Laboratories, не менее знакомыми Кеном Томпсоном и Деннисом Ритчи.

Как и остальные операционные системы того времени, UNIX был написан на ассемблере. Отладка программ на ассемблере настоящая мука. Томпсон решил, что для дальнейшей разработки ОС необходим язык высокого уровня и придумал небольшой язык B. За основу Томпсон взял язык BCPL. Язык B можно рассматривать как C без типов.

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

В противоположность повсеместному изменению синтаксиса, которое происходило во время создания B, основная семантика BCPL - его структура типов и правила вычисления выражений - осталась нетронутой. Оба языка - безтиповые, вернее имеют единственный тип данных - «слово» или «ячейка», набор битов фиксированной длины. Память в этих языках - массив таких ячеек, а смысл содержимого ячейки зависит от операции, которая к ней применяется. Например, оператор "+" просто складывает свои операнды при помощи машинной инструкции add, и другие арифметические операции также безразличны к смыслу своих операндов.

Ни BCPL, ни B, ни C не выделяют в языке символьные данные; они считают строки векторами целых чисел и дополняют общие правила несколькими соглашениями. И в BCPL, и в B строковый литерал означает адрес статической области инициализированный символами строки упакованными в ячейки.

Как создавался Си

В 1970 Bell Labs приобрела для проекта компьютер PDP-11. Так как B был готов к работе на PDP-11, Томпсон переписал часть UNIX на B.

Но модель B и BCPL подразумевала издержки при работе с указателями: правила языка, определяя указатель как индекс в массиве слов, делали указатели индексами слов. Каждое обращение к указателю при исполнении генерировало масштабирование указателя в адрес байта, который ожидал процессор.

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

В 1971 году Ритчи начал создавать расширенную версию B. Сначала он назвал её NB (New B), но когда язык стал сильно отличаться от B, название сменили на C. Вот что, писал об этом сам Ритчи:

Я хотел, чтобы структура не только характеризовала абстрактный объект, но и описывала набор бит, который мог быть прочитан из каталога. Где компилятор смог бы спрятать указатель, наname, которого требует семантика? Даже если бы структуры были бы задуманы более абстрактными, и место для указателей могло бы быть спрятано где-нибудь, как бы я решил техническую проблему корректной инициализации этих указателей при выделении памяти для сложного объекта, возможно структуры содержащей массивы, которые содержат структуры, и так до произвольной глубины?

Решение состояло в решительном скачке в эволюционной цепочке между безтиповым BCPL и типизированным C. Он исключал материализацию указателя в хранилище, а вместо этого порождал его создание, когда имя массива упоминалось в выражении. Правило, которое сохранилось и в сегодняшнем C, состоит в том, что значения–массивы, когда они упоминаются в выражении, конвертируются в указатели на первый из объектов, составляющих этот массив.

Второе нововведение, которое наиболее ясно отличает C от его предшественников, - вот эта более полная структура типов и особенно её выразительность в синтаксисе деклараций. NB предлагал основные типы int и char совместно с массивами из них и указателями на них, но никаких других способов скомпоновать их.

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



Изображение из книги «Язык Си»: M. Уэйт, С. Прата, Д. Мартин

Для любого объекта такого составного типа, уже был способ указать на объект, который является его частью: индексировать массив, вызвать функцию, использовать с указателем оператор косвенного обращения. Аналогичное рассуждение приводило к синтаксису объявления имён, который отражает синтаксис выражения, где эти имена используются. Так

объявляет целое, указатель на целое и указатель на указатель на целое. Синтаксис этих объявлений отражает тот факт, что i, *pi, и **ppi все в результате дают тип int, когда используются в выражении. Похожим образом
объявляют функцию, возвращающую целое, функцию возвращающую указатель на целое, указатель на функцию возвращающую целое;
объявляют массив указателей на целое, указатель на массив целых.

Во всех этих случаях объявление переменной напоминает её использование в выражении, чей тип – это то, что находится в начале объявления.

70-е годы: «смутное время» и лже-диалекты

Язык к 1973 стал достаточно стабилен для того, чтобы на нём можно было переписать UNIX. Переход на C обеспечил важное преимущество: переносимость. Написав компилятор C для каждой из машин в Bell Labs, команда разработчиков могла портировать на них UNIX.

По поводу возникновения языка Си Питер Мойлан в своей книге «The case against C» пишет: «Нужен был язык, способный обойти некоторые жесткие правила, встроенные в большинство языков высокого уровня и обеспечивающие их надежность. Нужен был такой язык, который позволил бы делать то, что до него можно было реализовать только на ассемблере или на уровне машинного кода».

C продолжил развиваться в 70-х. В 1973–1980-х годах язык немного подрос: структура типов получила беззнаковые, длинные типы, объединение и перечисление, структуры стали близкими к объектам–классам (не хватало только нотации для литералов).

Первая книга по Cи. Книга «Язык программирования Си», написанная Брайаном Керниганом и Деннисом Ритчи и опубликованная в 1978 году, стала библией программистов на Си. При отсутствии официального стандарта эта книга – известная также как K&R, или «Белая Книга», как любят называть поклонники си – фактически стала стандартом.


Изображение с сайта learnc.info

В 70-х программистов на Cи было немного и большинство из них были пользователями UNIX. Тем не менее, в 80-х Cи вышел за узкие рамки мира UNIX. Компиляторы Cи стали доступны на различных машинах, работающих под управлением разных операционных систем. В частности, Си стал распространяться на быстро развивающейся платформе IBM PC.

K&R ввёл следующие особенности языка:

Структуры (тип данных struct);
длинное целое (тип данных long int);
целое без знака (тип данных unsigned int);
оператор += и подобные ему (старые операторы =+ вводили анализатор лексики компилятора Си в заблуждение, например, при сравнении выражений i =+ 10 и i = +10).

K&R C часто считают самой главной частью языка, которую должен поддерживать компилятор Си. Многие годы даже после выхода ANSI Cи он считался минимальным уровнем, которого следовало придерживаться программистам, желающим добиться от своих программ максимальной переносимости, потому что не все компиляторы тогда поддерживали ANSI C, а хороший код на K&R C был верен и для ANSI C.

Вместе с ростом популярности появились проблемы. Программисты, писавшие новые компиляторы брали за основу язык, описанный в K&R. К сожалению, в K&R некоторые особенности языка были описаны расплывчато, поэтому компиляторы часто трактовали их на своё усмотрение. Кроме того, в книге не было чёткого разделения между тем, что является особенностью языка, а что особенностью операционной системы UNIX.

После публикации K&R C в язык было добавлено несколько возможностей, поддерживаемых компиляторами AT&T, и некоторых других производителей:

Функции, не возвращающие значение (с типом void), и указатели, не имеющие типа (с типом void *);
функции, возвращающие объединения и структуры;
имена полей данных структур в разных пространствах имён для каждой структуры;
присваивания структур;
спецификатор констант (const);
стандартная библиотека, реализующая большую часть функций, введённых различными производителями;
перечислимый тип (enum);
дробное число одинарной точности (float).

Ухудшало ситуацию и то, что после публикации K&R Си продолжал развиваться: в него добавлялись новые возможности и из него вырезались старые. Вскоре появилась очевидная необходимость в исчерпывающем, точном и соответствующем современным требованиям описании языка. Без такого стандарта стали появляться диалекты языка, которые мешали переносимости – сильнейшей стороне языка.

Стандарты

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

Разработкой стандарта языка Си занялся Американский национальный институт стандартов (ANSI). При нём в 1983 году был сформирован комитет X3J11, который занялся разработкой стандарта. Первая версия стандарта была выпущена в 1989 году и получила название С89. В 1990, внеся небольшие изменения в стандарт, его приняла Международная Организация Стандартизации ISO. Тогда он стал известен под кодом ISO/IEC 9899:1990, но в среде программистов закрепилось название, связанное с годом принятия стандарта: С90. Последней на данный момент версией стандарта является стандарт ISO/IEC 9899:1999, также известный как С99, который был принят в 2000 году.

Среди новшеств стандарта С99 стоит обратить внимание на изменение правила, касающегося места объявления переменных. Теперь новые переменные можно было объявлять посреди кода, а не только в начале составного блока или в глобальной области видимости.

Некоторые особенности C99:

Подставляемые функции (inline);
объявление локальных переменных в любом операторе программного текста (как в C++);
новые типы данных, такие, как long long int (для облегчения перехода от 32- к 64-битным числам), явный булевый тип данных _Bool и тип complex для представления комплексных чисел;
массивы переменной длины;
поддержка ограниченных указателей (restrict);
именованная инициализация структур: struct { int x, y, z; } point = { .y=10, .z=20, .x=30 };
поддержка однострочных комментариев, начинающихся на //, заимствованных из C++ (многие компиляторы Си поддерживали их и ранее в качестве дополнения);
несколько новых библиотечных функций, таких, как snprintf;
несколько новых заголовочных файлов, таких, как stdint.h.

Стандарт С99 сейчас в большей или меньшей степени поддерживается всеми современными компиляторами языка Си. В идеале, код написанный на Си с соблюдением стандартов и без использования аппаратно- и системно-зависимых вызовов, становился как аппаратно- так и платформенно-независимым кодом.

В 2007 году начались работы над следующим стандартом языка Си. 8 декабря 2011 опубликован новый стандарт для языка Си (ISO/IEC 9899:2011). Некоторые возможности нового стандарта уже поддерживаются компиляторами GCC и Clang.

Основные особенности С11:

Поддержка многопоточности;
улучшенная поддержка Юникода;
обобщенные макросы (type-generic expressions, позволяют статичную перегрузку);
анонимные структуры и объединения (упрощают обращение ко вложенным конструкциям);
управление выравниванием объектов;
статичные утверждения (static assertions);
удаление опасной функции gets (в пользу безопасной gets_s);
функция quick_exit;
спецификатор функции _Noreturn;
новый режим эксклюзивного открытия файла.

Несмотря на наличие стандарта 11 года, многие компиляторы до сих пор не поддерживают полностью даже версии C99.

За что критикуют Си

У него достаточно высокий порог вхождения, что затрудняет его использование в обучении в качестве первого языка программирования. Программируя на Си, нужно учитывать множество деталей. «Будучи рождён в среде хакеров, он стимулирует соответствующий стиль программирования, часто небезопасный, и поощряющий написание запутанного кода», пишет Википедия.

Более глубокую и аргументированную критику высказал Питер Мойлан. Он посвятил критике Си целых 12 страниц. Приведем пару фрагментов:

Проблемы с модульностью
Модульное программирование на языке Си возможно, но лишь в том случае, когда программист придерживается ряда довольно жестких правил:

На каждый модуль должен приходиться ровно один header-файл. Он должен содержать лишь экспортируемые прототипы функций, описания и ничего другого (кроме комментариев).

Внешней вызывающей процедуре об этом модуле должны быть известны только комментарии в header-файле.

Для проверки целостности каждый модуль должен импортировать свой собственный header-файл.

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

Прототипы функций можно использовать только в header-файлах. (Это правило необходимо, поскольку язык Си не имеет механизма проверки того, что функция реализуется в том же модуле, что и ее прототип; так что использование прототипа может маскировать ошибку «отсутствия функции» - «missing function»).

Любая глобальная переменная в модуле, и любая функция, кроме той, что импортируется через header-файл, должны быть объявлены статическими.

Следует предусмотреть предупреждение компилятора «вызов функции без прототипа» (function call without prototype); такое предупреждение всегда нужно рассматривать как ошибку.

Программист должен удостовериться в том, что каждому прототипу, заданному в header- файле, соответствует реализованная под таким же именем в том же модуле неприватная (т.е. нестатическая в обычной терминологии Си) функция. К сожалению, природа языка Си автоматическую проверку этого делает невозможной.

Следует с подозрением относиться к любому использованию утилиты grep. Если прототип расположен не на своем месте, то это, скорее всего, ошибка.

В идеале программисты, работающие в одной команде, не должны иметь доступа к исходным файлам друг друга. Они должны совместно использовать лишь объектные модули и header-файлы.

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



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

Можно различать важные и неважные указатели. Важным в нашем понимании считается указатель, необходимый для создания и поддержания структуры данных.

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

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

Вторая причина - правило языка Си, согласно которому все параметры функций должны передаваться по значению. Когда вам нужен эквивалент VAR-параметра языка Паскаль или inout- параметра языка Ada, единственное решение состоит в том, чтобы передать указатель. Этим во многом объясняется плохая читаемость программ на языке Си.

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

Си – жив

Согласно данным на июнь 2016 года, индекс TIOBE, который измеряет рост популярности языков программирования, показал, что C занимает 2 место:

Пусть кто-то скажет, что Си устарел, что его широкое распространение - следствие удачи и активного PR. Пусть кто-то скажет, что без UNIX язык Си никогда бы не создали. Добавить метки