Могу ли я отключить эти два правила MISRA: один оператор для каждой функции и обязательные прототипы функций?

Наша компания теперь соответствует стандарту ISO-13485 (медицинские приборы) и хочет использовать MISRAC2012. Я прочитал стандарт, но не могу понять, разрешено ли мне отключать некоторые правила, если я думаю, что это может улучшить как стабильность, так и читабельность.

Два примера:

MISRA допускает только 1 оператор возврата для каждой функции. Это часто приводит к вложенным условным структурам, которые выглядят как рождественская елка. Я действительно не думаю, что это правило повышает безопасность, поскольку делает код менее читаемым и более подверженным ошибкам.

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

Если я хочу отключить эти два правила, могу ли я это сделать? Кто-нибудь из клиентов обвинит меня в этом?


person nowox    schedule 03.10.2017    source источник


Ответы (3)


MISRA-C:2012 имеет 3 категории, по которым сортируются все директивы и правила:

  • Обязательный. Вы должны следовать им, и вам не разрешается делать отклонения.
  • Необходимый. Вы должны следовать им, но вам разрешено нарушать их, если вы заявляете о формальном отклонении от правила. Вам нужна веская причина, почему.
  • Консультативный. Рекомендуется следовать им, но вы можете нарушать их, не вызывая формального отклонения (хотя рекомендуется поднимать отклонение).

Идея, лежащая в основе отклонений, заключается в том, что в вашей компании должна быть рутина для их устранения, например, внутреннее поручение по обеспечению качества или что-то, что можно поднять на собраниях по проверке кода и т. д. Идея состоит в том, что кто-то еще, кроме вас, должен быть вовлечен в процесс создания отклонение, предпочтительно кто-то с обширными знаниями C. Это описано в MISRA-C 5.4, а также в дополнительном руководящем документе под названием Соответствие MISRA: 2016 может оказаться полезным.

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


Что касается одного оператора возврата для каждой функции, то, на мой взгляд, это известный дефект в MISRA-C, унаследованный от IEC 61508 ( Я думаю, что я единственный, кто действительно удосужился исследовать, откуда исходит требование). Вы должны выдвигать постоянное отклонение от правила, так как это ерунда. Лично я перефразировал требование как «функции не должны иметь более одного оператора возврата, если только несколько операторов возврата не приводят к более читаемому коду». Это охватывает то, что, как мы надеемся, было истинным намерением правила, а именно избежать программирования спагетти.


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

Я не верю, что это имеет какой-то смысл, похоже, вы пытаетесь решить проблему, которой не существует. Вам следует избегать случайной рекурсии, 1) зная, что вы делаете, и 2) используя инструменты статического анализа, как того требует MISRA.

Если вы хотите, чтобы стек вызовов был func1() -> func2() -> func3() и блокировал func2() или func3() от вызова func1(), это лучше всего решить с помощью надлежащего дизайна программы. Давая функциям интуитивно понятные имена и руководствуясь здравым смыслом, вы очень далеко продвинетесь.

Если этого недостаточно, вы можете разделить единицу перевода на две части и создать отдельную пару файлов h/c для внутренних компонентов. Риск, который вы описываете, в основном представляет собой проблему, если у вас есть очень длинные исходные файлы с множеством функций в них, до такой степени, что программист теряет их из виду. Это также является хорошим признаком того, что файл (и/или функции) следует разделить на несколько частей.

Что касается обоснования этого правила MISRA, то оно очень здравое, а именно: блокировать старое дерьмо C90 от «изобретения» соглашения о вызовах (неявный тип возвращаемого значения int, создание параметров и т. д.) только потому, что компилятор не может найти прототип функции. Вы точно не должны отступать от этого правила.

person Lundin    schedule 04.10.2017
comment
О, кстати, правило на самом деле говорит, что все функции должны иметь прототип, а не то, что все функции должны иметь предварительное объявление! Это разные вещи. См.: stackoverflow.com/a/43783993/584518 - person Lundin; 05.10.2017
comment
Не могли бы вы прилепить прототип функции непосредственно перед ее реальной реализацией? Я не читал правила, но, похоже, удовлетворяет MISRA принимает только функции, у которых есть прототип, но при этом не позволяет вам (или, по крайней мере, предупреждает вас, в зависимости от настроек компилятора), если вы попытаетесь переслать вызвать функцию? - person TripeHound; 05.10.2017
comment
Спасибо за этот замечательный ответ. О прототипах я создал отдельный вопрос здесь - person nowox; 05.10.2017
comment
Хороший ответ! И вы не одиноки, кто на самом деле проверял IEC 61508. Я также сделал это и пришел к мнению, что он предназначен для таких языков, как ассемблер или бейсик, где вы можете входить и выходить из функции практически где угодно. - person Melebius; 05.10.2017
comment
@Melebius IEC 61508:7 C.2.9 говорит (среди прочего), что подпрограммы должны иметь только одну запись и один выход. Обоснование не приводится. Одна единственная ссылка: Структурированный дизайн - Основы дисциплины проектирования компьютерных программ и систем. Э. Юрдон, Л. Л. Константин, 1979, ISBN 0-13-854471-9. ссылка на Amazon. - person Lundin; 05.10.2017
comment
Излишне говорить, что это старое дерьмо в основном не имеет отношения к обсуждению дизайна современных программ в 2017 году. В целом, IEC 61508 наполнен очень сомнительными источниками. (Например, Еженедельный информационный бюллетень от TUF, написанный на немецком языке. Не шучу.) И это стандарт, который инженеры используют для проектирования критических с точки зрения безопасности промышленных систем... - person Lundin; 05.10.2017
comment
Вы получаете +1 за возможность указать 61508 в качестве источника Руководства. - person Andrew; 13.10.2017
comment
@ Эндрю Не так сложно, поскольку это упоминается как в источнике, так и в обосновании правила :) В MISRA-C: 2004 единственное, что мы получили в качестве обоснования, было: Это требуется IEC 61508 при хорошем стиле программирования. Что меня тогда сильно задело. И затем, когда вы проверите, откуда 61508 взял это, это из какой-то книги по программированию динозавров 1978 года. Я несколько раз указывал комитету MISRA, что это недействительный источник, особенно во время обзора перед выпуском MISRA-C: 2012. Однако MISRA-C — не единственный стандарт, унаследовавший дефект, он также достался ISO 13849-1. - person Lundin; 13.10.2017
comment
Я знаю, Лундин, но удивительно, насколько избирательным может быть чтение людей :-) Эта тема постоянно пересматривается... как и в случае с goto, который был смягчен. - person Andrew; 16.10.2017
comment
@ Эндрю ... что тоже было ошибкой. Хотя вполне возможно использовать goto чистым и читаемым способом, в то же время можно написать тот же самый код без goto, но еще более читаемым способом: вместо использования goto при ошибке используйте возврат функции. То есть: goto — это 100% лишняя языковая фича. Не мешало бы и запретить, как в МИСРА-С2. В качестве побочного эффекта дебаты о goto, считающиеся вредными, будут запрещены в обзорах кода MISRA, что всегда приятно. - person Lundin; 16.10.2017
comment
Вау, почему бы просто не указать на разделы стандарта, а не на эти многословные самоуверенные ответы? Это то, что делает MISRA плохой репутацией. Да, было бы большим вредом запретить [goto] его. Запрещение — глупое слово, оно мало уважает проверку кода (и процесс отклонения), что и является реальной точкой зрения, не говоря уже о том, что есть очень веские причины, когда они (gotos) оправданы. Если вы мне не верите, то попробуйте провести некоторое время в обзорах кода и выбрать свои сражения... - person Veriloud; 26.11.2017
comment
@Veriloud Что касается ответов, основанных на вариантах: глядя на ваш собственный ответ, в нем полностью отсутствуют ссылки (в отличие от моего) и он на 100% состоит из мнений. Единственная часть этого ответа (комментарии не являются частью ответа на SO), основанная на мнении, заключается в том, что я указываю, что правило об одном единственном операторе return на самом деле основано на мнении. MISRA унаследовала его от IEC 61508, который унаследовал его от древней книги по программированию 1979 года. Если мнение основано на том, что критически важные для безопасности системы в 2017 году не должны проектироваться на основе устаревших книг по программированию 1979 года, то так и должно быть. Это. - person Lundin; 27.11.2017
comment
@Veriloud Что касается goto: общепризнанно, что единственное допустимое использование goto — это конструкции ошибок goto — безусловные переходы вниз для целей обработки ошибок. Но вместо того, чтобы использовать шаблоны перехода при ошибке, опытные программисты склонны использовать type wrapper (void) { init(); type result = func(); clear(); return result; }, где func — это функция, которая возвращает значение при ошибке. Демонстрируя это программистам во время код-ревью, они почти всегда перестают использовать goto. Это на 100% лишняя языковая особенность, которая только создает бессмысленный конфликт. - person Lundin; 27.11.2017
comment
@Lundin, AFA «одиночные возвраты», вы говорите, что отклонения вообще не должны выполняться в каждом конкретном случае», а затем предлагаете перефразировать, если несколько операторов возврата не приведут к более читаемому коду». Когда/как/что определяет «читабельный код»? Из ваших мнений следует, что отклонения - это не решение, а обременительный формальный процесс. Вся идея точного правила заключается в автоматическом просмотре кода ради эффективного ручного просмотра, который по определению проводится в каждом конкретном случае. Прежде чем сказать, что я в ла-ла-ленде (так случилось, в отпуске), да, я понимаю реалии некоторых бюрократий. - person Veriloud; 05.12.2017
comment
@Lundin, AFA старые «дебаты о переходе», нет, не собираюсь туда, но я вижу еще одну причину, по которой вам не нравится правило «единого возврата» ;-) Я предполагаю механизм отклонения, который также сильно автоматизирован. и тесно интегрирован с хорошими инструментами статического анализа/контроля версий/проверки кода. Это также делает автоматическую проверку кода на пороговых значениях метрик сложности как проверку спагетти (и «читабельного кода») более управляемой. Хорошие инструменты также должны легко справляться с исключениями, чтобы они не испортили вашу идею обертки ;-). - person Veriloud; 05.12.2017

Правило 15.5 (Функция должна иметь единственную точку выхода в конце) является рекомендательным правилом. Таким образом, если ваши внутренние процессы документируют это, вы можете отменить это правило.

Правило 8.2 (Функции должны быть в форме прототипа) является Обязательным правилом по (ИМХО) разумной причине, поскольку оно гарантирует, что вы явно определяете тип и номер возвращаемого значения функции. и типы всех параметров, что позволяет избежать неопределенного поведения.

Если вы того пожелаете, вы можете отклониться от руководства, но для этого вам нужно обосновать это решение!

person Andrew    schedule 13.10.2017

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

Итак, как бы вы обосновали отклонения в масштабах всего проекта, о которых вы просите?

Я бы сказал, что в лучшем случае каждое отдельное нарушение должно быть рассмотрено. В некоторых случаях ваши рассуждения, например, глубокая вложенность может быть нечитаемой/неподдерживаемой, должны быть взвешены вопросом, почему они вообще такие глубокие? Другими словами, возможно, функция делает слишком много и ее нужно разбить на более мелкие модули.
Я предполагаю, что вы используете инструмент статического анализа, который достаточно умен, чтобы предоставить возможность не сообщать о нарушении после того, как отклонение было одобрено.

person Veriloud    schedule 03.10.2017
comment
Лично я считаю, что отклонения в масштабах проекта не должны допускаться, а все отклонения должны быть в масштабе всей компании, поскольку именно так мы пишем безопасный C. По моему опыту, правила MISRA попадают в три категории: всегда имеет смысл, никогда не имеет смысла и имеет смысл, за исключением некоторых случаев. Все это можно выяснить заранее. Например, требование следовать ISO C всегда должно отклоняться во встроенных системах, потому что вам всегда будет нужен встроенный ассемблер и прерывания. Допустимые исключения из правил могут быть перечислены в документации об отклонении. - person Lundin; 04.10.2017
comment
Я согласен с вашей идеей для всей компании - и (лично) закрепил многие такие отклонения (особенно относящиеся к Рекомендательным правилам, но также и к тем, которые вы цитируете) в стандартах кодирования компании. Важно, чтобы отклонение или отклонение заявления было одобрено на соответствующем уровне. Кроме того, я рад обсудить то, что вы считаете бессмысленным :-) - person Andrew; 16.10.2017
comment
Не все компании разрабатывают критически важные для безопасности программы одинакового уровня, так что нет, я не согласен. - person Veriloud; 26.11.2017