3.2.9 Требования к языкам для управляющих систем
Требования к языкам формируются исходя из общих требований:
надёжность, реальное время.
Приветствуются:
• Простота;
• Выразительность;
• Ортогональность.
К примеру, Perl не подходит, между языками Си и Си++ выбираем Си.
Почему?
3.2.10 Краткий обзор языков, используемых при проектировании
ВВС
3.2.10.1 Язык программирования Си
Си (англ. C) – императивный язык программирования или язык, в основе
которого лежит модель вычислений Фон-Неймана. Используется практически
на всех уровнях пирамиды автоматизации. Наибольшее распространение
получил на нижних (3 и 4) уровнях пирамиды.
3
В случае, если не использовать use strict
143
Простота, легкость переноса компиляторов на разные аппаратные
платформы, наличие указателей и битовых операций делает удобным
использование языка Си для системного программирования, программирования
встроенных систем и микроконтроллеров. Аскетичность языка Си с одной
стороны, функциональность и мощь с другой, хорошо укладываются в принцип
KISS
4
.
Язык программирования Си разработан в начале 1970-х годов
сотрудниками Bell Labs Кеном Томпсоном и Денисом Ритчи как развитие языка
Би. Си был создан для использования в операционной системе (ОС) UNIX. С
тех пор он был перенесен на многие другие операционные системы и стал
одним из самых используемых языков программирования.
Си ценят за его эффективность; он является самым популярным языком
для создания системного программного обеспечения. Его также часто
используют для создания прикладных программ. Несмотря на то, что Си не
разрабатывался для новичков, он активно используется для обучения
программированию. В дальнейшем синтаксис языка Си стал основой для
многих других языков.
Для языка Си характерны лаконичность, современный набор конструкций
управления потоком выполнения, структур данных и обширный набор
операций.
Многие элементы Си потенциально опасны, а последствия неправильного
использования этих элементов зачастую непредсказуемы. Керниган говорит:
«Си – инструмент, острый, как бритва: с его помощью можно создать и
элегантную программу, и кровавое месиво». В связи со сравнительно низким
уровнем языка многие случаи неправильного использования опасных
элементов не обнаруживаются и не могут быть обнаружены ни при
компиляции, ни во время исполнения. Они часто приводит к непредсказуемому
поведению программы. Иногда в результате неграмотного использования
элементов языка появляются уязвимости в системе безопасности. Необходимо
заметить, что использования многих таких элементов можно избежать.
Чаще всего источником ошибки является обращение к несуществующему
элементу массива. Несмотря на то, что Си непосредственно поддерживает
статические массивы, он не имеет средств проверки индексов массивов
(проверки границ). Например, возможна запись в шестой элемент массива из
пяти элементов, что, естественно, приведёт к непредсказуемым результатам.
Частный случай такой ошибки называется ошибкой переполнения буфера.
Ошибки такого рода приводят к большинству проблем с безопасностью.
Другим потенциальным источником опасных ситуаций служит механизм
указателей. Указатель может указывать на абсолютно любой объект в памяти,
4
Принцип "KISS" (англ. Keep It Simple, Stupid- "будь проще, тупица") - процесс и принцип
проектирования, при котором простота системы декларируется в качестве основной цели и/или ценности.
144
включая даже и сам машинный код программы, что может приводить к
непредсказуемым эффектам. Несмотря на то, что большинство указателей, как
правило, указывают на безопасные места, они легко могут быть передвинуты в
уже небезопасные области памяти с помощью арифметики указателей; память,
на которую они указывают, может быть освобождена и использована по-
другому («висячие указатели»); они могут быть не инициализированы («дикие
указатели»); или же они просто могут получить любое значение путём
приведения типов или присваивания значения другого повреждённого
указателя. Другие языки пытаются решить эти проблемы путём использования
более ограниченных типов – ссылок.
Одна из таких проблем заключается в том, что автоматически и
динамически создаваемые объекты не инициализируются, поэтому в начале они
имеют такое значение, какое осталось в памяти, выделенной для них от ранее
удалённых объектов. Такое значение полностью непредсказуемо, оно меняется
от одной машины к другой, от запуска к запуску, от вызова функции к вызову.
Если программа попытается использовать такое неинициализированное
значение, то придёт к непредсказуемому результату. Большинство
современных компиляторов пытаются обнаружить эту проблему в некоторых
случаях.
Функции с переменным количеством аргументов также являются
потенциальным источником проблем. В отличие от обычных функций,
имеющих прототип, стандартом не регламентируется проверка функций с
переменным числом аргументов. Если передаётся неправильный тип данных, то
возникает непредсказуемый, если не фатальный результат. Например,
семейство функций printf стандартной библиотеки языка Си, используемое для
генерации форматированного текста для вывода, хорошо известно своим
потенциально опасным интерфейсом с переменным числом аргументов,
которые описываются строкой формата. Проверка типов в функциях с
переменным числом аргументов является задачей каждой конкретной
реализации такой функции, однако многие современные компиляторы
проверяют типы в каждом вызове printf, генерируя предупреждения в случаях,
когда список аргументов не соответствует строке формата. Следует заметить,
что невозможно статически проконтролировать даже все вызовы функции
printf, поскольку строка формата может создаваться в программе динамически,
поэтому, как правило, никаких проверок других функций с переменным числом
аргументов компилятором не производится. Для помощи программистам на Си
в решении этих и многих других проблем было создано большое число
отдельных от компиляторов инструментов. Такими инструментами являются
программы
дополнительной
проверки
исходного
кода
и
поиска
распространённых
ошибок,
а
также
библиотеки,
предоставляющие
дополнительные функции, не входящие в стандарт языка, такие как проверка
границ массивов или ограниченная форма сборки мусора.
145
Ещё одной распространённой проблемой является то, что память не может
быть использована снова, пока она не будет освобождена программистом с
помощью функции free(). В результате программист может случайно забыть
освободить эту память и продолжить её выделять, занимая всё большее и
большее пространство. Это обозначается термином утечка памяти. Наоборот,
возможно освободить память слишком рано, но продолжать её использовать.
Из-за того, что система выделения может использовать освобождённую память
по-другому, это ведёт к непредсказуемым последствиям. Эти проблемы
решаются в языках со сборкой мусора. С другой стороны, если память
выделяется в функции и должна освобождаться после выхода из функции,
данная проблема решается с помощью автоматического вызова деструкторов в
языке C++, или с помощью локальных массивов, используя расширения С99.
Основная масса инструментального обеспечения для разработки
встраиваемых систем продается за деньги. Стоимость компиляторов или
наборов инструментальных средств составляет от сотен до нескольких тысяч
евро.
Сравнительно небольшое количество производителей микропроцессоров
предлагает свои компиляторы бесплатно (для примера AVR Studio фирмы
Atmel и Softune Workbench фирмы Fujitsu).
Коммерческие компиляторы имеют следующие характерные особенности:
• Официальная поддержка;
• Хорошая документация;
• Меньшее количество ошибок в генерируемом коде (к сожалению, не
всегда и не у всех);
• Улучшенная оптимизация кода;
• Более дружелюбный интерфейс пользователя.
Как правило, начинающие разработчики гораздо проще разбираются в
коммерческих инструментальных средствах.
Некоторое количество компиляторов, используемых во встроенных
системах, выпускается под лицензией GNU GPL. GNU General Public License
(иногда переводят, как, например, Универсальная общественная лицензия
GNU, Универсальная общедоступная лицензия GNU или Открытое
лицензионное соглашение GNU) – лицензия на свободное программное
обеспечение, созданная в рамках проекта GNU в 1988 г. Её также сокращённо
называют GNU GPL, или даже просто GPL, если из контекста понятно, что речь
идёт именно о данной лицензии (существует довольно много других лицензий,
содержащих слова «general public license» в названии).
Цель GNU GPL – предоставить пользователю права копировать,
модифицировать и распространять (в том числе на коммерческой основе)
программы (что по умолчанию запрещено законом об авторских правах), а
также гарантировать, что и пользователи всех производных программ получат
вышеперечисленные права. Принцип «наследования» прав называется
146
«копилефт» (транслитерация английского «copyleft») и был придуман Ричардом
Столлмэном. По контрасту с GPL, лицензии собственнического ПО очень редко
дают пользователю такие права и обычно, наоборот, стремятся их ограничить,
например, запрещая восстановление исходного кода.
Использование свободно распространяемых инструментальных средств
порождает некоторое количество проблем.
• Существует необходимость в достаточно высоком начальным уровне
подготовки разработчика.
• Свободно-распространяемые
компиляторы
генерируют
менее
эффективный код.
• Официальная поддержка отсутствует (тем не менее, присутствует
неплохая неофициальная).
В целом, инструментальные средства выпущенные в рамках лицензии GPL
являются в некоторых случаях очень неплохой альтернативой коммерческим
продуктам [38, 39, 46].
Достарыңызбен бөлісу: |