Муфты электромонтажные от производителя Fucon
РадиоЛоцман - Все об электронике

Языки программирования встраиваемых систем

Журнал РАДИОЛОЦМАН, март 2015

Colin Walls

EE Times

Вебинар «Как выбрать идеальный силовой модуль: решения SUNCO для силовой электроники» (03.12.2024)

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

Все это началось в прошлом году, когда я получил письмо от Клайва (Макса) Максфилда. Он проводил семинар в Design West, и поинтересовался, хочу ли я принять в нем участие. Семинар назывался «10 языков за 45 минут». Суть заключалась в том, что выступят десять участников, каждому из которых будет отведено четыре минуты для рассказа о конкретном языке, имеющем отношение к разработчикам встраиваемых систем. Оставшиеся пять минут рассчитаны на вступление Макса и заключительную речь. Он попросил меня рассказать о C++, и я был счастлив принять его приглашение.

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

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

Языки программирования встраиваемых систем

Во многих отношениях программирование встраиваемых систем не слишком отличается от написания кода для настольного компьютера, но есть некоторые ключевые различия.

  1. Во встраиваемых системах ресурсы (память и мощность процессора) ограниченны. А настольные системы, как обычно предполагается, не имеют никаких ограничений.
  2. Встраиваемые системы, как правило, работают в режиме реального времени.
  3. Количество операционных систем для настольных компьютеров невелико. Для встраиваемых систем существует множество вариантов, в том числе работа «на голом железе» (то есть вообще без операционной системы).
  4. Аппаратная часть всех персональных компьютеров в первом приближении одинакова. Но каждая встраиваемая система уникальна, поэтому здесь более распространено программирование, приближенное к аппаратному.

На заре становления встраиваемых систем из-за фактора №1 и, в некоторой степени, №2 и №4 большинство систем программировалось на ассемблере. Такой подход и сейчас остается в качестве одного из вариантов, но теперь ассемблер используется только тогда, когда обойтись без него действительно невозможно.

Потребности разработчиков встраиваемых систем достаточно специфичны, поэтому можно было бы ожидать, что специализированные языки были разработаны для удовлетворения их уникальных требований. Есть примеры языков, которые изначально создавались для встраиваемых приложений (например, PL/M, Forth, Ada), но они не нашли всеобщего признания.

Язык C

Язык Си был разработан в 1970-х Деннисом Ритчи (Dennis Ritchie) в AT&T Bell Labs. Си основывался на более ранней попытке создать высокоуровневый язык под названием B, обладавший преимуществами ассемблера. Он, в свою очередь, начал разрабатываться в Кембридже (Англия) и первоначально носил название BCPL. Оригинальный справочник «Язык программирования Си» (The C Programming Language), написанный Брайаном У. Керниганом (Brian W. Kernighan) и Деннисом М. Ритчи, был опубликован в 1978 году. Для полной стандартизации (в соответствии с ANSI) потребовалось еще 10 лет, и с тех пор вышло много версий.

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

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

Ниже приведен пример хорошо скомпонованного кода.

int x, y, z;

for (x = 0; x < 4; x++)
{
z = strlen(bullets[x]);
for (y = 0; y < z; y++)
{
blab(bullets[x][y]);
}
}

Следующий стиль написания немного компактнее, но при этом код все еще полностью работоспособен.

for (int x = 0; x < 4; x++) {
for (int y = 0; y < strlen(bullets[x]); y++) {
blab(bullets[x][y]);
}
}

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

for(int x=0;x<4;x++) for(int y=0;ystrlen(bullets[x];y++) blab(bullets[x][y]);

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

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

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

Язык C++

Хотя идея объектно-ориентированного программирования (ООП) не нова (по крайней мере, один такой язык существовал в середине 1960-х годов), модным ООП стало лишь в 1980-х. В результате появился целый ряд языков, некоторые из которых были основаны на Си. Видимо, теперь самое время посмотреть на «родословную» языков программирования, показанную ниже.

Языки программирования встраиваемых систем
«Генеалогическое дерево» языков программирования.

Некоторое количество C-подобных объектно-ориентированных языков выжило, но единственным языком, который действительно утвердился и теперь популярен в области разработки встраиваемых систем, является C++. Он был создан Бьерном Страуструпом (Bjarne Stroustrup) в Bell Labs.

Одним из ключевых факторов успеха C++ была его первоначальная реализация. Вместо того, чтобы писать обычный компилятор, Страуструп написал препроцессор – «Cfront», который переводил C++ в стандартный Си. Это означало, что новый язык был готов для использования практически в любом месте, где был доступен компилятор Си. В настоящее время очень распространены специальные компиляторы C++, но мощный стимул его развитию дало именно создание препроцессора.

Цель ООП – поддерживать разработку крупных программных проектов. Такая задача все чаще встает перед разработчиками встраиваемых систем. Использование подхода ООП может позволить каждому программисту сосредоточиться на его или ее собственной области знаний без необходимости понимания каждого аспекта всего приложения.

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

Ключевой особенностью языка C++ является понятие класса. Класс в C++ представляет собой нечто подобное структуре в языке Си, но с некоторыми отличиями:

  • Класс может содержать как код, так и данные.
  • Код и данные могут быть скрыты от пользователей класса.
  • В класс могут быть включены специальные функции, чтобы позволить операторам определить эту функцию с экземплярами класса.
  • Класс, по существу, представляет собой новый тип данных; экземпляры класса называются «объектами».
  • Синтаксис определения объекта проще, чем экземпляров структуры, достаточно просто сослаться на имя класса.

Ниже приведен простой пример определения класса в C++.

class woport
{
int shadow;
int* address;
public:
woport(long);
~woport();
void operator|=(int);
void operator&=(int);
}

Обратите внимание на то, как объект (или, если хотите, переменная) out объявлена вполне обычным способом, и естественно используется со знакомыми операторами. Автору этой функции main() не нужен доступ к исходному коду функций в классе woport.

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

Java

Язык Java был разработан Джеймсом Гослингом (James Gosling) в Sun Microsystems (теперь часть корпорации Oracle) и выпущен в 1995 году. Оригинальная концепция Гослинга заключалась в создании надежного языка, который мог бы быть использован для написания портируемых приложений для встраиваемых систем. На протяжении многих лет язык Java успешно применялся в качестве средства запуска программ (апплетов) в браузере. Это позволяло разработчикам выполнять размещаемые на веб-страницах сложные приложения, которые будут работать в любом браузере на любой платформе.

Языки программирования встраиваемых систем
Официальная эмблема языка Java.

Позже использование языка Java стало больше соответствовать его первоначальной концепции как инструмента включения развернутых приложений во встраиваемые устройства. Такая практика является обычной в операционной системе Android.

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

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

В Java нет указателей, что снижает вероятность возникновения ошибок программирования. Неотъемлемой частью языка является многопоточность, а благодаря сложному механизму «сбора мусора» очень хорошо работает динамическое распределение памяти.

Вот пример кода на Java:

BitSet mask = new BitSet();
mask. set(cpuId);
AffinitySet as = AffinitySet.generate (mask);
AffinitySet.set(as, thread);

Java работает только на 32- и 64-разрядных устройствах. Исполнительной системе требуется немало ресурсов центрального процессора. Впрочем, благодаря тому, что 32-разрядные микроконтроллеры становятся очень дешевыми, область применения Java расширяется.

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

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

JavaScript

JavaScript был разработан в Netscape в 1995 году. Его название сбивает с толку, поскольку этот язык не имеет никакой реальной связи с Java. Выбор такого названия был только маркетинговым ходом.

Языки программирования встраиваемых систем
Неофициальный логотип JavaScript.

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

Программирование на JavaScript может быть очень продуктивным – многое доступно даже с ограниченными знаниями языка. Это делает язык привлекательным для непрограммистов, а также объясняет изобилие плохо написанного кода на JavaScript.

JavaScript был первоначально задуман как средство, наделяющее веб-страницы возможностями программирования, и в такой роли он сейчас используется почти повсеместно. Любая сделанная в современном стиле веб-страница использует JavaScript. Он был назван «Ассемблер для Web». (По-видимому, кем-то, кто не был знаком с программированием на ассемблере). Кроме того, JavaScript является сердцем HTML 5, который получает все большее распространение.

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

Ниже показан пример кода на JavaScript, который был встроен в HTML-файл.

script
function fact(x)
{
if (x == 0)
return 1;
return x * fact(x - 1);
}

alert(fact(4));

/script

Python

Еще один язык, который впервые появился в начале 1990-х годов – Python – был создан Гвидо ван Россумом (Guido van Rossum). Он замышлялся как скриптовый язык, однако его мощности достаточно для разработки намного более сложных приложений.

Языки программирования встраиваемых систем
Логотип языка Python.

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

Ниже приведен пример кода на Python.

def remove_dupes(mylist):
mylist.sort()
last = mylist[-l]
for i in range(len(mylist)-2, -1, -1):
if last == mylist[i]:
del mylist[i]
else:
last = mylist[i]

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

Философия Python заключается в следующем:

  • Красивое лучше, чем некрасивое.
  • Явное лучше, чем неявное.
  • Простое лучше, чем сложное.
  • Сложное лучше, чем очень сложное.
  • Читаемость имеет значение.

Python широко используется во встраиваемых приложениях и имеет гораздо больше возможных областей применения, где его уникальный стиль будет полезен. Написанные на Python программы легко портируются, поэтому язык может использоваться где угодно. Не так давно разработчики дешевого одноплатного компьютера Raspberry Pi выбрали Python в качестве основного языка программирования.

Выводы и благодарности

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

Я с благодарностью принимаю неоценимую помощь, которую получил в процессе подготовки и написания этой статьи от Клайва Максфилда и других докладчиков и авторов Design West: Дуэйна Бенсона (Duane Benson), Дэвида Бебермана (David Beberman) и Марка Гуадженти (Mark Guagenti).

Перевод: Mikhail R по заказу РадиоЛоцман

На английском языке: Embedded Systems Programming Languages

Электронные компоненты. Скидки, кэшбэк и бесплатная доставка от ТМ Электроникс
Для комментирования материалов с сайта и получения полного доступа к нашему форуму Вам необходимо зарегистрироваться.
Имя