`

СПЕЦІАЛЬНІ
ПАРТНЕРИ
ПРОЕКТУ

Чи використовує ваша компанія ChatGPT в роботі?

BEST CIO

Определение наиболее профессиональных ИТ-управленцев, лидеров и экспертов в своих отраслях

Человек года

Кто внес наибольший вклад в развитие украинского ИТ-рынка.

Продукт года

Награды «Продукт года» еженедельника «Компьютерное обозрение» за наиболее выдающиеся ИТ-товары

 

Си-клон Cyclone

Статья опубликована в №27 (546) от 18 июля

0 
 

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

Итак, вместо забавной, но совершенно бесполезной реализации на системном уровне базы знаний с механизмами логического вывода и встроенным клоном функционального языка программирования Lisp (в действительности во всем этом интересным является только попытка выяснить, кому и зачем было надо превращать прикладную программу в операционную систему), мы поговорим о разработке куда более приземленной. И, что особенно приятно, речь пойдет не о сырой вечно недоделанной поделке, в которой всегда нужно исправить самую малость, а о вполне «съедобной» программе, весьма стабильно работающей на разнообразных платформах, в том числе самых распространенных (что, впрочем, не помешало автору «побаловаться» ею в операционной среде ОС Minix 3). Хотя последнее и неудивительно – проект Cyclone начинался в знаменитых лабораториях AT&T, что является лучшей визитной карточкой для любой, даже самой альтернативной, разработки.

Итак, краткое представление предмета обсуждения завершено, и мы, как обычно, начнем с главного – поиска ответа на вопрос: «А оно мне надо?». Действительно, кому нужен еще один язык программирования (а именно о нем пойдет речь), да еще и какой-то малоизвестный и никем особо не поддержанный, когда уже существуют сотни замечательных разработок с грудой инструментальных средств и многотонной поддержкой технической литературой? Вопрос, безусловно, серьезный, и ответ на него в общем виде дать, наверное, невозможно: уверенное «никому» означает, что, например, такой отличный набирающий популярность язык как Ruby не имеет права на существование; уверенное «всем» – что отвечающий – «пионэр». Поэтому вместо ответа, который каждый должен дать сам, автор предлагает небольшое отступление, демонстрирующее как минимум то, что в мире языков программирования до идиллии бесконечно далеко.

В первой половине мая конференция JavaOne в Сан-Франциско преподнесла забавный сюрприз. Оказалось, что слоган Java «Напиши один раз – исполняй везде», – это всего лишь слоган. То есть нечто, ни к чему фактически не обязывающее. В противном случае крупнейший разработчик встраиваемого ПО для мобильных телефонов (и самих телефонов, безусловно) Motorola и создатель ведущего инструментального окружения Eclipse Foundation не ставили бы открыто вопрос о растущей фрагментации платформы JavaME и тревожной ситуации с совместимостью пользовательских программ для этой платформы. Ведущий архитектор и генеральный директор подразделения мобильных устройств Motorola Марк ВанденБринк охарактеризовал ситуацию так: «Сегодня в мире портативной техники есть много версий Java, так как различные компании реализуют эту платформу по-своему. Реальным стимулом индустрии стал бы переход к единой платформе».

C другой стороны, наличие проблем с Java косвенно подтверждается результатами традиционного анализа сбыта технической литературы, проводимого заслуженно уважаемой компанией O'Reilly. На конец апреля (т. е. приблизительно одновременно с конференцией JavaOne) покупатели технической литературы продемонстрировали устойчивый рост интереса к платформе .NET и языкам C# и Visual Basic и подтвердили устойчивый же спад интереса к Java. В то же время взрывная популярность совсем свежего «еще одного» языка Ruby буквально смела с полок все посвященные ему издания. Ключевые слова «Extreme programming» в названии книг перестали радовать продавцов – аудитория потребителей рун экстремального программирования сократилась на 41%. Впрочем, им на смену пришли почитатели «Agile programming» – их стало на 43% больше. А вот число желающих освоить принципы управления программными проектами возросло в два с лишним раза. На 10% уменьшилось количество покупателей литературы о Linux, при этом интерес к учебникам по дистрибутивам Red Hat сократился на 52%.

И, наконец, последнее в нашем отступлении. Хотите верьте, хотите нет, но в середине 2006 г. более 90% окружающего нас программного обеспечения разрабатывалось на языке C. С учетом этого все вышесказанное может означать только одно: кумиры приходят и уходят, а C до сих пор остается важным инструментом. Именно поэтому мощные инструментальные средства, позволяющие разрабатывать качественные C-программы, своей важности не теряют. Вот теперь самое время задаться вопросом: «Так все-таки, о чем пойдет речь – о языке программирования или инструментальном средстве разработки качественных C-программ?». И о том, и о другом – именно по этой причине Cyclone и интересен, и именно из-за этого ему можно простить отсутствие мощной поддержки. Впрочем, всему свое время...

Си-клон

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

Мощь, выразительность и гибкость С обеспечиваются вовсе не синтаксическими особенностями этого языка, а его практически полной идентичностью с низкоуровневыми средствами программирования, такими как машинные коды и ассемблер. Язык С допускает такие конструкции, как «область памяти произвольного размера», адрес этой области памяти и указатель на эту область – и все это благодаря спецификатору так называемого неполного типа (incomplete type) void. Более того, согласно стандарту ISO IEC 9899 тип void не просто неполон, т. е. не содержит информации о размере хранящегося в нем объекта, а принципиально не может быть дополнен такой информацией. Это означает, что void-область памяти – великолепный контейнер для помещения в нее чего угодно и вытворения с этим чем угодно чего вздумается программисту без единой претензии со стороны компилятора. Полная свобода. Расплата за которую всегда одна – потенциальная опасность. Достаточно неудачно сместить указатель на void-область памяти и произвести запись в адресуемую им ячейку, чтобы программа эффектно прекратила свое функционирование. То есть – стала некачественной. А так как работа с областями памяти, указателями и адресами в С – это фактически основные механизмы языка, возможностей сделать программу некачественной даже у хорошего программиста предостаточно.

В Cyclone для того, чтобы сократить количество этих возможностей до минимума предусмотрены совершенно новые для C сущности. Во-первых, язык предлагает явное определение для области памяти – так называемый регион (region, иногда называется также ареной или зоной). Эта скрытая структура данных, сопровождающая каждый объект или множество объектов Cyclone, в большинстве случаев создается компилятором и хранит информацию об области памяти, в которой объект располагается. Это дает возможность во время исполнения программы контролировать факт наличия области памяти, например по указателю на объект. Если соответствующий регион не существует, то, естественно, и обращение по указателям на объекты, расположенные в нем, невозможны. Кроме дополнительных механизмов контроля, с помощью регионов в Cyclone реализован весьма эффективный сборщик мусора (garbage collector). Основные типы регионов, в принципе, не преподносят неожиданностей – так, регионы стека (stack region) предназначены для размещения локальных переменных и автоматически создаются/удаляются в соответствии с традиционными для языков блочной структуры правилами, а регион кучи (heap region) также традиционно используется для выделения динамической памяти под создаваемые программистом объекты, именно этими объектами из этого региона оперирует сборщик мусора.

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

Кроме областей памяти, модификациям в Cyclone подверглись и связанные с ними сущности – указатели. Как и в C, в Cyclone указатели остались, по сути, адресами, и синтаксис операций с ними фактически не изменился. Но система регионов и возможности контроля во время исполнения привели к тому, что семантика этих операций во многом отличается и определяется специфическими особенностями указателей, которые в явном виде могут указываться программистом с помощью спецификаторов (qualifiers). Самый простой, тонкий указатель в Cyclone, не влекущий никаких накладных расходов во время исполнения и самый близкий к указателям C, специфицируется следующим образом:

тип *@thin имя ;

В этом выражении @thin – характерный для Cyclone спецификатор, в остальном же сохранен традиционный синтаксис C. Это означает, что если с помощью препроцессора заменить @thin на пробел или пустую строку, предыдущее выражение станет вполне законным и для C. «Тонкие» указатели Cyclone практически ни в чем не отличаются от C-аналогов, но до тех пор, пока вы не попытаетесь применить адресную арифметику. Компилятор запрещает в арифметических выражениях использование @thin-указателей, и хоть как-то обойти это ограничение можно только в одном случае – когда множество адресуемых объектов представляет собой последовательность и содержит уникальный объект, играющий роль явного признака ее окончания. Очевидный пример такой последовательности – строка в C, а уникальными объектами традиционно являются значения целочисленного 0 и NULL. Для указателей на подобные объекты в Cyclone предусмотрен спецификатор @zeroterm. Упомянув ранее, что запрет на «тонкую» адресную арифметику с помощью этого спецификатора можно обойти «хоть как-то», мы подразумевали, что Cyclone не дает полной свободы и при адресации динамических последовательностей. Например, программисту не разрешено перемещаться по последовательности в направлении ее первого элемента, что означает, что в адресной @zeroterm-арифметике с «тонкими» указателями приращения могут быть только положительными. Это ограничение, дополненное скрытой от программиста генерацией кода, проверяющего допустимость указателя, позволяет избежать многих трудно обнаруживаемых ошибок.

Там, где есть «тонкие» указатели, должны быть и «толстые». В Cyclone для них предусмотрен спецификатор @fat. Их можно использовать в операциях адресной арифметики без всяких ограничений и угрозы потери качества программы. Достигается это, естественно, избыточностью и дополнительными накладными расходами на этапе исполнения. В каждом «толстом» указателе хранятся, по сути, три «тонких» – собственно на объект в последовательности и на ее начало и конец. Для таких указателей компилятор сгенерирует скрытый код, проверяющий допустимость операций адресной арифметики.

Еще одна вариация «толстого» безопасного указателя в Cyclone определяется спецификатором @numelts (количество_элементов). Для такого указателя проверяется факт вхождения указываемого объекта в упорядоченную последовательность с номерами объектов от 0 до количество_элементов-1. Это, естественно, наиболее удобно при работе с массивами.

Если предыдущие модификации C-оригинала в Cyclone можно условно назвать одновременно качественными и щадящими (по ранее упомянутой причине – с помощью препроцессора Cyclone-код можно легко трансформировать в легальный C-код), то практически все последующее уже – высокоуровневые модификации языка, отдаляющие Cyclone от своего прототипа (в принципе, пользоваться ими совершенно не обязательно).

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

typedef struct ListElement<`t>
 
`t Element ;
struct List_Element<`t> * NextElement ;
struct List_Element<`t> * PrevElement ;
ContListElem<`t> ;

В принципе, описание вполне очевидное – в качестве параметра здесь используется `t и, например,

ContListElem ListIntsElem ;

объявляет и создает элемент списка из целых чисел.

Наряду с полиморфными типами Cyclone допускает и создание полиморфных функций. Но с некоторыми ограничениями, не свойственными, в частности, аналогичным механизмам С++ (шаблонам). Так, полиморфные функции в Cyclone не могут быть параметризованы никакими иными типами, кроме целочисленного и указателей.

Из ряда функциональных языков Cyclone позаимствовал механизм автоопределения типа объявляемой переменной в соответствии с результатами инициализирующего ее значение выражения. Для поддержки такой возможности, называемой «пусть-инициализацией» (let initialisation), в языке предусмотрено ключевое слово let. Общий синтаксис его применения следующий:

let шаблон = выражение_с_результатом_типа_T ;

Семантически это эквивалентно такой традиционной для C записи:

T шаблон = выражение_с_результатом_типа_T ;

но с важным существенным отличием – выражение может возвращать множество значений, а шаблон – описывать контейнерный объект (например, структуру), и в результате выполнения let-инициализации полям этого объекта будут присвоены значения подходящих типов.

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

abstract struct Stack<`t> ... ;

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

И все-таки...

Вот и наступило время еще раз определиться с назначением Cyclone и целесообразностью его использования. Учитывая невысокую популярность и слабую поддержку, его высокоуровневые модификации не так интересны, как мощные механизмы контроля времени исполнения работы с памятью. Именно благодаря им Cyclone становится полезным инструментальным средством прототипирования C-программ. Вы можете «обкатать» Cyclone-прототипы и, убедившись в их корректности, безболезненно превратить их в C-код. Механизмы контроля во время исполнения Cyclone считаются более чем неплохими и сравнимыми по качеству с хорошими коммерческими аналогами, реализованными на уровне библиотек.

Ready, set, buy! Посібник для початківців - як придбати Copilot для Microsoft 365

0 
 

Напечатать Отправить другу

Читайте также

 

Ukraine

 

  •  Home  •  Ринок  •  IТ-директор  •  CloudComputing  •  Hard  •  Soft  •  Мережі  •  Безпека  •  Наука  •  IoT