Библиографическое описание:

Чегодаев Н. И. Сравнительный обзор распространённых языков программирования для микропроцессорных систем // Молодой ученый. — 2011. — №10. Т.1. — С. 92-95.

В настоящее время для микроконтроллеров фирмы Atmel существует множество языков программирования: от классического BASCOM-AVRBasic[1] до Assembler и C. Наиболее распространёнными являются язык ассемблера и язык C. В этих языках реализованы практически все возможности программирования встраиваемых систем на данном типе микроконтроллеров[2].

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

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

Как известно, все существующие языки программирования можно разделить на две основные категории:

  1. языки программирования низкого уровня;

  2. языки программирования высокого уровня.

К первой группе относят семейство языков ассемблера, например, Turbo Assembler, Macro Assembler. Эти средства разработки позволяют получить наиболее короткий и быстродействующий код.

Ко второй группе относятся упомянутые выше BASCOM-AVRBasic и язык программирования C.

Известно, что язык C, в некотором роде, занимает промежуточное положение, объединяя возможности языков высокого уровня с функциональностью языков ассемблера[3], однако, это не совсем так. Основные функции языков ассемблера имеют основанием низкоуровневый доступ к компьютеру, определяющий полноценную возможность управления процессором, что, с одной стороны, позволяет достигать максимальной скорости реакции программы на действия пользователя[4, с. 10], а с другой стороны позволяет достичь определённых преимуществ в размере конечного исполняемого кода программ[2].

У опытных программистов на языках высокого уровня, к которым всё-таки относится и язык программирования C, часто возникают возражения по описанным выше вопросам, основанные на том, что некоторые операторы языка C или даже Turbo Pascal напрямую преобразуются в машинные коды. Также допустимо утверждать, что такие языки программирования как FORTH обеспечивают непосредственный низкоуровневый доступ. Но несмотря на то, что C или иные языки программирования обеспечивают выполнение некоторых низкоуровневых операций, эти языки всё равно не могут сравниться с языком ассемблера в возможностях доступа к процессору [4, с. 9]. Высокоуровневые языки, несмотря на наличие возможности выполнения низкоуровневых операций, требуют комбинирования своих функций с функциями языка ассемблера, путём встраивания ассемблерного кода в код программ, написанных на этих языках[4, с.11][4, с.332][4, с.358].

Как уже было отмечено выше, ассемблер – это низкоуровневый язык программирования, что позволяет достичь значительного уровня оптимизации уже при непосредственном написании кода программы. При этом оптимизация достигается уже при программировании и её уровень контролируется непосредственно. Фактически, программируя, мы одновременно оптимизируем программу. При использовании автоматических компиляторов необходима синтетическая оптимизация. В настоящее время при программировании на языке C используются так называемые оптимизирующие компиляторы или оптимизаторы кода, например, компилятор фирмы Microsoft, упомянутый в статье [5].В таких системах оптимизация программного кода происходит при компиляции программы, то есть при преобразовании исходного текста программы в машинный код.

В настоящее время не существует единого мнения по вопросам доверия оптимизации, выполненной автоматически.

Обоснованием позиции, опирающейся на не совершенство синтетической оптимизации, может служить тестовый обзор [6]. Известно, что оптимизирующие компиляторы разных производителей имеют значительные различия при работе с различными комбинациями программного кода и по-разному переводят его в мнемонику конкретного микроконтроллера. Несмотря на то, что ядро и система команд микроконтроллеров AVR создавались в тесном сотрудничестве с фирмой IAR Microsystems, производителем компиляторов для языков программирования C/C++, как показано в обзоре [6] при использовании данного оптимизатора кода, также возможны неточности при генерации ассемблерных мнемокодов.

Несмотря на то, что автоматическая оптимизация кода значительно ускоряет разработку программ, часто она может приводить к трудно обнаруживаемым ошибкам конечного программного кода, рассмотрим следующий пример [7]:
unsigned short  int i;

void main (void)
{
DDRB  = 255;
PORTB = 0;
  while(1)
  {
    	if (PINB == 255) PORTB = 0;
    	else PORTB++;
    	for (i=0; i<10000; i++){}
	//Далее может быть иной программный код}}

Пример представляет собой программу на языке программирования C для микроконтроллера фирмы Atmel, семейства AVR. В верхней строке программы объявляется глобальная переменная i типа без знаковое короткое целое (unsigned short int), которая согласно [3, с. 18] имеет размер два байта и может принимать значения от 0 до 65535. Данная переменная будет использоваться позднее для организации цикла задержки. Далее происходит инициализация аппаратных портов ввода-вывода микроконтроллера. Внутри бесконечного цикла while(1), значимость которого при программировании микроконтроллеров рассмотрена ниже, расположен программный код, изменяющий значение на контактах порта B микроконтроллера AVR по следующему правилу: если на всех контактах порта B обнаруживаются потенциалы единицы, то обнулить контакты, иначе увеличить значение в регистре-защёлке порта B. Последний цикл без выполняемого в теле кода предназначен для формирования задержки вывода для того, чтобы изменение потенциалов порта B можно было зафиксировать, например, с помощью светодиодов. Далее следует комментарий.
Если включить автоматическую оптимизацию, то компилятор сочтёт цикл задержки бесполезной тратой времени и исключит его из программы[7]. Таким образом, изменение параметров порта B не может быть зафиксировано. Если же программная задержка важна для разрабатываемой системы, то последствия могут оказаться непредсказуемыми.
Из вышесказанного можно заключить, что автоматическая оптимизация на данном этапе своего развития нуждается в изменениях и доработках и к её использованию не следует прибегать повсеместно, что делает её малозначительным преимуществом языков программирования высокого уровня.
В большинстве публикаций, посвящённых языку ассемблера [4, с. 11], указывается на непереносимость и аппаратную зависимость программ, написанных на нём, по сравнению с языками высокого уровня, такими как C. Однако, программы на языке C также могут быть аппаратно зависимыми и вследствие чего непереносимыми, особенно, при работе с графическими контроллерами. Некоторые функции неработоспособны при программировании под графические контроллеры различных производителей. Таким образом, приходится разрабатывать различные наборы функций для прямого взаимодействия с драйверами видеокарт [8, с.249].  Кроме того, программы автоматической оптимизации кодов, созданные для языка C, о которых написано выше, сами являются аппаратно зависимыми и непереносимыми, например, считающийся одним из лучших компиляторов Intel C Compiler производит некорректную оптимизацию программ для процессоров других производителей [9].
	Известно утверждение, что программирование на языке ассемблера затруднено слабой читаемостью программ, что в свою очередь приводит к большему числу ошибок при программировании на этом языке, нежели на языке программирования C  [2]. В данном случае читаемость программ, как и количество в них ошибок, занесённых при программировании, зависит в большей степени от опыта, внимательности и стараний программиста, а также от того факта, насколько хорошо известен разработчику тот или иной язык программирования[4, с. 11]. Кроме того, за якобы лучшей читаемостью программ, написанных на языке программирования C, скрывается множество недокументированных возможностей, как отрицательно, так и положительно влияющих на правильную работу конечного программного продукта. Язык программирования C – громоздкий язык. Таким образом, хотя разработка программ на языке C, при поверхностном взгляде, быстрее программирования на языке ассемблера, однако программирование на нём требует знания нюансов, без которых написание корректно работающих программ невозможно [10, с.104]. Язык ассемблера, в свою очередь, представляет собой набор простых правил, изучив которые, можно уверенно программировать на нём, а знание и изучение архитектуры целевой микропроцессорной системы упрощает процесс программирования и последующего чтения программ [7]. 
Сегодня большинство программистов убеждены, что одним из основных преимуществ языка C по отношению к языку ассемблера является наличие библиотечных программ, например, подпрограмм вычисления сложных выражений, вида (x* 2 + 8) [4, с.11]. Несмотря на удобство программирования с их использованием, следует признать, что отсутствие встроенных библиотечных программ, скорее преимущество языка ассемблера, нежели его недостаток, так как при использовании таких программ в языках высокого уровня теряется возможность полного управления ресурсами компьютера и, следовательно, возможность написания максимально эффективных, быстрых и компактных программ, кроме того существует большое количество ассемблерных библиотек, позволяющих выполнять операции, характерные для языков высокого уровня[4, с.11], например, стандартные библиотеки адресации для микроконтроллеров фирмы Atmel, позволяют обращаться к регистрам и портам микроконтроллера аналогично программам на C, в противном случае пришлось бы вручную изучать адреса регистров и вносить их в управляющие конструкции [11].
Из всего вышесказанного может сложиться впечатление, что автор данного обзора является противником программирования на языке C. Это не так, в течение пятнадцати лет программирования автора, из которых десять лет посвящено изучению языка C, к изучению которого автор приступил ранее, чем к изучению языка ассемблера, был сделан вывод, что последний оказался практически эффективнее по сравнению с языком программирования C. В условиях программирования малых микропроцессорных систем и однокристальных микро-ЭВМ, к которым относятся микроконтроллеры, в частности фирмы Atmel, а такие технические особенности этих микроконтроллеров, как развитая регистровая память, включающая тридцать два регистра общего назначения, исключают необходимость использования сложных высокоуровневых языков программирования, хотя и допускают её [11].
Как можно заключить из вышеописанного, преимущества языка программирования C достаточно спорны. В настоящее время он обладает одним принципиальным преимуществом, а именно знакомство с ним большинства программистов, которые программировали на нём изначально для персональных компьютеров с процессорами архитектуры x86. Особенностью такой архитектуры является наличие единственного регистра, в общем используемого и для пересылок и для арифметических операций[4, с.53], в этих условиях переход к высокоуровневым языкам является естественным, но, как уже было замечено выше, технические особенности архитектуры Enhanced RISC, микроконтроллеров фирмы Atmel позволяют отказаться от высокоуровневых языков при программировании[11]. Таким образом, если большинство программистов по каким-то причинам не пожелали использовать или изучить язык ассемблера, язык программирования C подходит для использования в случаях, когда группа программистов работает над программным кодом для одной задачи. Здесь требуется достоверная читаемость кода каждым из них субъективно, и язык C становится своеобразным «Lingua Franca» программирования, подобно английскому языку. Для написания же эффективных, быстродействующих и компактных программ язык ассемблера предпочтительнее языка C.
Общение автора данного обзора с программистами систем на микроконтроллерах, работающих с языком C и знающих его достаточно хорошо, показали, что они по непонятным причинам демонстрируют нежелание изучать и использовать язык ассемблера. Несмотря на то, что они часто сталкиваются с описанными выше «подводными камнями» языка при отладке программ, тратя на неё при этом значительное количество времени, язык ассемблера вызывает у них отторжение, как на техническом уровне, так и психологически. Причин неприязни они, зачастую, не называют, либо говорят об описанных выше спорных.
Как говорил классик программирования Дональд Кнут, «каждый, кто всерьёз интересуется компьютерами, должен рано или поздно изучить по крайней мере один машинный язык» [7].  Как показал опыт автора, проблемы в освоении языка ассемблера, связаны с недостаточным знанием английского языка. Язык ассемблера – необычный компьютерный язык. Почти весь текст исходной программы состоит из непроизносимых слов cli, movsb, sbb [4, c. 17] в архитектуре x86, или ADD, TST, SBR, CBR,  RJMP [11] в архитектуре RISC, микроконтроллеров AVR, фирмы Atmel. Человек, не владеющий английским языком в должной мере, предпочитает распространённые языки программирования высокого уровня, где операторы если и не постигаются интуитивно, то зачастую имеют многозначное толкование в соответствии с множеством вариантов использования. Программисты запоминают операторы высокоуровневых языков программирования, в большей степени основываясь не на логике, которое несёт название функции, а на логике выполняемых оператором действий. Например, студенты, изучающие немецкий язык, при изучении языка программирования BASIC, часто неверно произносят названия функций и команд данного языка программирования, но это не мешает им постигать программирование на этом языке [12, с. 5]. При изучении языка ассемблера мнемонические операторы имеют в большинстве случаев однозначное соответствие между названием оператора и выполняемым им действием и изучение в этом случае должно также основываться на знании, понимании и правильной интерпретации названий и расшифровок операторов для успешного программирования в будущем. Например, упоминавшийся выше, оператор cli, означает clear if, то есть сброс флага разрешения прерываний if и представляет собой сокращение [4, с.484], а оператор SBR аббревиатуру от Set Bit(s) in Register [12] и т.п. Кроме того, опыт автора показал, что большинство руководств по языку ассемблера для микроконтроллеров имеют также ошибки, намеренно или случайно допущенные при переводе на русский язык, и программа, написанная с использованием таких руководств неработоспособна. Только при использовании оригинальных, зачастую англоязычных руководств по применению языка ассемблера становится возможным их практическое применение, что является ещё одним стимулом к изучению английского языка программистами.
Отдельно хотелось бы заметить, что хотя язык ассемблера считается языком программирования для профессионалов [13, с. 104] [14 c. 130] он не так сложен. Преимуществами языка ассемблера является, низкоуровневый доступ к процессору, достижение максимальной скорости за счёт возможности полностью управлять процессом вычисления, компактность и скорость программ [4, с.10]. Программам на языке ассемблера присуща точность исполнения заложенного алгоритма в отсутствии описанных выше нюансов, основанных на своеобразном «языковом барьере» между высокоуровневым языком программирования и реальным вычислительным процессом, так как программы на языках высокого уровня преобразуются в машинные коды опосредованно посредствам промежуточного языка, ассемблерные мнемонические операторы имеют прямое соответствие «код-машинная операция»  [3],[4], [13],[14]. Как уже отмечалось выше, язык ассемблера чрезвычайно эффективен в условиях систем на микроконтроллерах фирмы Atmel, также большинство программ для микроконтроллерных систем сохранили условности характерные для традиционных технологий программирования, при которых имеется ограничение на используемые вычислительные ресурсы и от программ требуется прежде всего эффективность и компактность [15]. При таких условиях, в большинстве случаев, возможностей языка ассемблера достаточно, а возможности языка C избыточны.
В заключение хотелось бы процитировать авторитетного автора, специалиста по языку ассемблера, Тома Свана, в предисловии к своей книге «Освоение Turbo Assembler» он пишет: «…если кто-то вам говорил, что ассемблер очень сложен, не верьте.»[4, с.5].

Литература:
  1. Atmel AVR Basic Compiler (BASCOM) // Официальный сайт [Электронный ресурс] – режим доступа: http://microcontrollershop.com/product_info.php?products_id=352
  2. Программирование микроконтроллеров AVR // Электронный журнал «Мой робот» [Электронный ресурс] – режим доступа: http://myrobot.ru/stepbystep/mc_programming.php
  3. Глушаков, С.В., Программирование на C++ [Текст]  / C.В. Глушаков, Т.В. Дуравкина – М.:АСТ, 2008 – 685 с.
  4. Сван, Том, Освоение Turbo Assembler: Пер. с англ. [Текст] / Том Сван – К.;М.;СПб.: Диалектика, 1996 – 544 с.
  5. Оптимизация компилятора // Электронный журнал «Техника оптимизации» [Электронный ресурс] – режим доступа: http://howoptimize.ru/optimization.html
  6. Missed Optimization // Электронный журнал «EasyElectronics.ru» [Электронный ресурс] – режим доступа: http://we.easyelectronics.ru/AVR/missed-optimization.html
  7.  Ассемблер или C? // Электронный журнал «Controller systems» [Электронный ресурс] – режим доступа: http://controllersystems.com/books/praktika_programmirovaniya_atmel_avr/assembler-ili-s.html
  8. Фленов, Михаил, Искусство программирования игр на C++ [Текст] // Михаил Фленов – СПб.:БХВ-Петербург, 2006 – 256 с.
  9. Придётся ли Intel убрать из компилятора функцию, намеренно выдающую плохой код для процессоров AMD? // Электронный журнал «Железные войны» [Электронный ресурс] – режим доступа: http://www.holyware.ru/viewtopic.php?f=52&t=2296
  10. Касперски Крис, Сишные трюки // Крис Касперски – журнал «Хакер», август 2008 (116) 2008, с.104
  11. Atmel AVR ATiny213 Datasheet // Atmel Microcontroller Manuals [Электронный ресурс] – режим доступа: http://www.myrobot.ru/downloads/datasheet_t2313.php
  12. Сафронов И., Бейсик в задачах и примерах [Текст] // И.Сафронов – Д.;К.;М.;СПб.: БХВ-Петербург, 2000 – 224 с.
  13. Авдюхин, Алексей,  Высокий уровень программирования // Алексей Авдюхин – журнал «Хакер», июль 07 (127) 2009, с.104
  14. Лебединский, Юрий, Роман с ВМ // Юрий Лебединский – журнал «PC Magazine Russian Edition – Компьютер сегодня», №1 (127), январь 2002, с. 130
  15. Павловская, Т.А., C/C++ Программирование на языке высокого уровня [Текст] / Т.А.Павловская – СПб.:Питер, 2004 – 461с.

Обсуждение

Социальные комментарии Cackle