Дык на чем писать-то?

Опубликовано в рубрике "Статьи", 8 января, 2010.
Тэги: , , автор:

Среди эмбеддеров живы споры по поводу того – на каком языке лучше писать программы для контроллеров. Одни ратуют за ассемблер – мол, быстрее, компактнее, другие, те что за Си говорят, что на нем программы быстрее пишутся, а по скорости совсем слегка проигрывают ассемблеру. Оба этих класса эмбеддеров катят бочку на тех, кто пользуется C++: мол, он слишком медлителен прожорлив и опасен для встраиваемых систем. Ну что, устроим холивор?

image 

Приоритеты

Первое, с чем нужно определиться – это по какому критерию сравнивать языки. По моему мнению, основные критерии таковы (в порядке уменьшения важности):

 

  1. Сложность модифицирования и поддержки кода
  2. Скорость написания программы
  3. Предсказуемость (безопасность) кода
  4. Скорость выполнения кода
  5. Размер кода

 

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

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

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

Предсказуемость (безопасность) – для обычного ширпотребного софта баги совершенно нормальны и никуда от них не денешься, но чем меньше их будет, тем выше будет ваша репутация. Совсем другое дело в промышленности, в военке, в медицине и в силовой бытовухе. Представьте, что кофемолка самопроизвольно включается когда вы лезете пальцами чтобы достать перемолотое. А вместо пальцев достаете кровавое месиво. Обидно?

Скорость выполнения для большинства приложений не очень актуальна. Если программа работает медленно – возьмите процессор побыстрее. Если партия устройств меньше 1000шт, то такой подход весьма оправдан. возможность отобрать рынок у конкурентов стоит гораздо больше. Часто применимо такое правило — не оптимизируйте код (по скорости) до тех пор, пока вы не упретесь в границы производительности. И когда упретесь, оптимизация должна быть обоснована показаниями профайлера, а не пустыми домыслами.

Размер кода, точно так-же как и скорость – код слишком велик? Берем больше памяти и готово.

 

Размышления

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

Правда, есть места либо особо критичные к производительности (к примеру, софт-драйвер USB от obdev), либо такие, где без ассемблера вообще невозможно обойтись (к примеру, watchdog timer msp430 требует записи в разные регистры через определенное количество тактов). Хотя, современные умные компиляторы автоматически генерируют правильный код в последнем случае.

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

С другой стороны – все сложно. Использовать ли “фишки” С++, кроме синтаксических? Использовать ли ООП ?

Linus Torvalds однажды выразил свое мнение по поводу C++:

C++ is a horrible language. It’s made more horrible by the fact that a lot
of substandard programmers use it, to the point where it’s much much
easier to generate total and utter crap with it. Quite frankly, even if
the choice of C were to do *nothing* but keep the C++ programmers out,
that in itself would be a huge reason to use C.

In other words: the choice of C is the only sane choice. I know Miles
Bader jokingly said "to piss you off", but it’s actually true. I’ve come
to the conclusion that any programmer that would prefer the project to be
in C++ over C is likely a programmer that I really *would* prefer to piss
off, so that he doesn’t come and screw up any project I’m involved with.

C++ leads to really really bad design choices. You invariably start using
the "nice" library features of the language like STL and Boost and other
total and utter crap, that may "help" you program, but causes:

- infinite amounts of pain when they don’t work (and anybody who tells me
   that STL and especially Boost are stable and portable is just so full
   of BS that it’s not even funny)

- inefficient abstracted programming models where two years down the road
   you notice that some abstraction wasn’t very efficient, but now all
   your code depends on all the nice object models around it, and you
   cannot fix it without rewriting your app.

In other words, the only way to do good, efficient, and system-level and
portable C++ ends up to limit yourself to all the things that are
basically available in C. And limiting your project to C means that people
don’t screw that up, and also means that you get a lot of programmers that
do actually understand low-level issues and don’t screw things up with any
idiotic "object model" crap.

(http://thread.gmane.org/gmane.comp.version-control.git/57643/focus=57918)

Как видите, Линус разделяет мою таблицу приоритетов и настаивает на том, что использование C++ приводит к плохим архитектурам программ.

Это не так. Главное отличие C++ от С – более глубокая инкапсуляция. Классы, контроль доступа, конструкторы/деструкторы ссылки и перегрузка — все это вместе со строгой проверкой типов делает вероятность ошибки меньше.

Рассмотрим пару случаев:

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

    Правильно, создает структуру по типу

    typedef struct { …object’s context… } objName;

    а потом для каждого объекта создает экземпляр этой структуры и вызывает функции типа

    objName_DoThing( &objName, thing_to_do );

 

знакомо? Вот, это типичные случаи, когда С-программист выполняет работу С++ компилятора.

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

Насчет тяжеловесности С++ кода, не поспоришь. Однако, 10-15% прирост “массы” не является сильно критичным в современном мире.

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

 

Итак, мой подход к языку

Я всегда пишу в режиме С++, используя его синтаксис.

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

Там-где может быть создано несколько экземпляров объекта, я предпочитаю пользоваться  классами С++, дабы не выполнять дурную работу.

Что касается ассемблера, я использую его только там, где без него нельзя обойтись.

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

 

С какого языка начинать обучение?

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

Страуструп (чувак, который придумал С++) рекомендует начать обучаться сразу с С++, дабы сразу мыслить объектах. Я считаю, что это мнение оправданно для компьютеров, где ОО подход стал стандартом, но не подходит для эмбеддера, где нужно знать тонкие механизмы.

Итак, сначала ассемблер, потом Си и потом С++.

 

Запомните, написать плохо можно на любом языке. Написать хорошо можно только на том языке, который дает возможность написать хорошо.




Комментарии
  1. Westbam написал(а) 8 января, 2010 в 20:33

    Мне кажется asm для 8 битных мк, хороший выбор.
    Я прогаю avr на ассемблере, и не испытываю ни каких проблем.
    На счет сложности модификации кода под какаю нить фенечку, ты загнул :) Имея исходник не проблема добавить лишнюю фишку.
    Не понятно зачем для устранения бага нужно переписывать всю прогу? У меня проблема бага решается, переписыванием участка кода и все.

    BSVi Reply:

    У вас просто совсем простые программы. Для них, да, ассемблер — лучший выбор. Проблемы начинаются когда размер программы становится больше 10тыс сишных строк.

    >Не понятно зачем для устранения бага нужно переписывать всю прогу?
    Читайте внимательнее. Там написано «ЕСЛИ придется переписывать — будет обидно.», у вас решается переписыванием куска кода потому, что вы знаете свой ассемблер и свою программу. Поработав с другим ассемблером и над другой программой вернутся к текущей будет очень сложно, а во время исправления бага наплодите кучу других.

    Я сам много писал на асме. Сейчас я боюсь читать свои старые поделки. И недайбог что-то в них менять!

  2. Westbam написал(а) 10 января, 2010 в 19:46

    Убедил :) Пойду зубрить Си.

    BSVi Reply:

    Ооо, хоть кого-то на путь истинный поставил )

  3. Detruanto написал(а) 21 февраля, 2010 в 13:59

    >у вас решается переписыванием куска кода потому, что вы знаете свой ассемблер и свою программу

    Самое страшно начинается, когда программу надо переделать через 5-6 месяцев (или через год-два)… Обычно даже Сишная программа кажется чужой и не очень знакомой=) Хотя, может это у меня так.

    З.Ы. От желания писать на ассемблере избавился на 4-м курсе, после просмотра программы моего сокурсника… 8 листов кода 10-м шрифтом… С двух сторон. о_О

  4. sea написал(а) 19 мая, 2010 в 7:10

    По поводу переписывания всей программы на ASM не было ни когда — то что написано выше это БРЕД одного человека. С++ язык для глючнутых устройств !!! И для тех БАРАНОВ кто не знает железа !!!. За всё время не видел ни одного устройства написанного на С++ чтоб не глючило, даже промышленного изготовления. Ведь всё равно из С++ получается ASM который УЖАСЕН, жрёт ресурсы микроконтроллера и главное ГЛЮЧИТ, так лучше сразу писать на ASMe. Ещё есть тупое начальство наслышенное о С++ и когда говоришь что ASM круче, так они считают тебя дураком. Говорят все пишут на С++ !!! (потому что, эти ВСЕ — ДЕБИЛЫ и в железе нихр..а не понимают.) ! Так что, если хотите чтоб ваше устройство вечно глючило пишите на С++ !!!

    BSVi Reply:

    А вы писали программу длиннее 10тыс строк на ассемблере?

    sea Reply:

    Есть у меня такие программы. Я пишу всегда с комментариями и даже спустя год без проблем в ней разбираюсь. У меня набралась огромная библиотека подпрограмм и сейчас я только вставляю их в новые программы, тем самым я могу посоревноваться по скорости написания с тем кто пишет на C++. А следовательно и по надёжности работы устройства. Если вы уже путаетесь в таких объёмах программы – это значит вы так их пишите, что сами потом разобраться не можете. Например: есть люди которые пишут плохим почерком (на бумаге), а потом сами прочесть не могут !!! Всё зависит не от языка, а от программиста. Ассемблер – это основной язык, всё остальное создаётся для основной масы БАРАНОВ населения (как и все другие языки программирования) !!!

    BSVi Reply:

    >Я пишу всегда с комментариями и даже спустя год без проблем в ней разбираюсь.
    Я тоже пишу с комментариями, не особо помогает.

    >У меня набралась огромная библиотека
    А у меня есть доступ не только к моей, но и огромной базе чужих исходников. К примеру, чтобы запустить стек TCP/IP или файловую систему мне понадобится пара часов времени. А вам?

    >А следовательно и по надёжности работы устройства
    Совершенно не следовательно. Ваши программы могут быть глючными, а куски в связи — тем более.

    >Ассемблер – это основной язык
    Нет, основной язык — это машинный код, ассемблер создан для БАРАНОВ

    sea Reply:

    По поводу TCP/IP у меня есть проект с модемом Simcom. Конечно я потратил побольше времени чем пару часов, за то работает безупречно ! Глючит сам Simcom (прошивка которого написана на С++ и портит свой IMEI, приходится перепрошивать его). Ещё он виснет, на что пришлось дополнить схему отключением питания, только после этого он запускается из зависания.
    ВЫ> Нет, основной язык – это машинный код.
    Ещё раз, Ассемблер — это основной язык !!! из которого получается прямой машинный код !!! (Не надо путать!)

    BSVi Reply:

    >TCP/IP у меня есть проект с модемом Simcom
    TCP/IP содержится в прошивке модема, а не написано вами, вы написали просто пулялку команд в модем.

  5. SchDoc написал(а) 18 июня, 2010 в 23:37

    Для меня ломание копий по поводу на чем писать было решено года три тому назад, когда я написал свое Windows приложение на C, размер файла который был всего 1744 байта (с ресурсом меню) и 1424 байта (без ресурса меню) !. Это произошло после долгого анализа работы нескольких компиляторов, а самое главное понимания опций компилятора из командной строки. Причина поисков уменьшения размеров была банальна, я не хотел писать стандартные части кода на ASM для своих первых ви:ру:сов (была у меня когда то такая слабость) :).
    В среде написания ПО для контроллеров та же ситуация. Четкое понимание работы C/C++ компилятора и его опций приводит к уменьшению времени написания софта при той же эффективности кода. В свою очередь ставится под вопрос нужно ли вообще писать всю прогу на ASM(е).
    В конце же скажу что из всех компиляторов код которых я анализировал после оптимизации лучшим (и более “вылизанным”) на данный момент оказался код IAR AVR (для MCU Atmel 8bit), возможно потому что это коммерческий продукт который имеет постоянную доработку кода компилятора.

    BSVi Reply:

    IAR AVR — очень крутой компилятор, но и он имеет ограничения. Некоторые куски которые он творит — весьма неоптимальны. Поэтому совсем уж критичные места приходится писать на асме. Но только совсем критичные.

  6. vitimo написал(а) 13 ноября, 2011 в 17:50

    Що для Atmega8 можно писати на С++? А що тоді там влізе?
    Три Int та вивід на LCD. А 32 bit арифтметика? А для чого тоді
    тішити себе що в ній 20 МГц? Дивився до Протеуса є приміри на С там щось зробленно на Atmega8… Жахи… два стека, бескінечне перезавантаження
    регістів тільки щоб розкрутити 1-Wire протокол. 20% в остатку…
    Вважаю С для виликих CPU. А в ASM теж є бібліотеки.

    BSVi Reply:

    Да влезет все, что и на си. Ведь си — подмножество С++

    >Вважаю С для виликих CPU. А в ASM теж є бібліотеки.
    Так мыло в прошлом веке. Сейчас для больших компью.теров есть Java и Python, а для контроллеров — С++. Уверен, что через десяток лет уже будут споры — что юзать для контроллеров Java или C++ и фанаты олдскула будут радовать за плюсы :)

  7. Panda_Y2K написал(а) 23 января, 2012 в 20:27

    Обычно комментарии не пишу, но в данном случае не удержался, готов подписаться под каждым словом автора. Полностью согласен.

    Panda_Y2K Reply:

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

Создать новую ветку комментариев


Вы должны войти или зарегистрироваться чтобы оставить комментарий.