В этой главе описывается стиль исходного кода, предпочитаемый командой разработчиков LinuxCNC.
1. Не навреди
При внесении небольших изменений в код в стиле, отличном от описанного ниже, соблюдайте местный стиль кодирования. Быстрые переходы от одного стиля кодирования к другому ухудшают читабельность кода.
Никогда не проверяйте код после выполнения над ним «отступа». Изменения пробелов, внесенные отступом, затрудняют отслеживание истории изменений файла.
Не используйте редактор, который вносит ненужные изменения в пробельные символы (например, заменяет 8 пробелов табулятором на строке, не измененной иным образом, или переносит строки, не измененные иным образом).
2. Табуляторы
Табуляция всегда соответствует 8 пробелам. Не пишите код, который правильно отображается только с другим значением позиции табуляции.
3. Отступ
Используйте 4 пробела на уровень отступа. Объединение 8 пробелов в один табулятор допустимо, но не обязательно.
4. Размещение скобок
Поместите открывающую фигурную скобку последней в строке и поставьте закрывающую фигурную скобку первой:
if (x) { // сделать что-то подходящее }
Закрывающая фигурная скобка находится на отдельной строке, за исключением случаев, когда за ней следует продолжение того же оператора, т. е. «while» в do-операторе или «else» в if-операторе , например :
do { // что-то важное } while (x > 0);
и
if (x == y) { // делать одно } else if (x < y) { // делать другое } else { // делать третье }
Такое размещение фигурных скобок также минимизирует количество пустых (или почти пустых) строк, что позволяет одновременно отображать большее количество кода или комментариев в терминале фиксированного размера.
5. Именование
C — спартанский язык, и таким же должно быть ваше именование. В отличие от программистов Modula-2 и Pascal, программисты C не используют милые имена, такие как ThisVariableIsATemporaryCounter. Программист на C назвал бы эту переменную tmp, что намного проще написать и не в последнюю очередь сложнее понять.
Однако описательные имена для глобальных переменных обязательны. Назвать глобальную функцию «foo» — это преступление.
ГЛОБАЛЬНЫЕ переменные (используются только в том случае, если они действительно нужны) должны иметь описательные имена, как и глобальные функции. Если у вас есть функция, которая подсчитывает количество активных пользователей, вы должны назвать это count_active_users() или аналогично, вы не должны называть ее cntusr()
Кодирование типа функции в имени (так называемая венгерская нотация) — это мозговой косяк — компилятор и так знает типы и может их проверить, а это только путает программиста. Неудивительно, что Microsoft делает глючные программы.
Имена ЛОКАЛЬНЫХ переменных должны быть короткими и точными. Если у вас есть счетчик циклов со случайными целыми числами, его, вероятно, следует назвать «i». Называть его loop_counter непродуктивно, если нет шансов, что его неправильно поймут. Точно так же «tmp» может быть переменной любого типа, которая используется для хранения временного значения.
Если вы боитесь перепутать имена локальных переменных, у вас есть другая проблема, которая называется синдромом дисбаланса функции-гормона-роста. См. следующую главу.
6. Функции
Функции должны быть короткими и приятными, и делать только одну вещь. Они должны умещаться на одном или двух экранах текста (как мы все знаем, размер экрана ISO/ANSI составляет 80x24) и делать одну вещь, и делать это хорошо.
Максимальная длина функции обратно пропорциональна сложности и уровню отступа этой функции. Таким образом, если у вас есть концептуально простая функция, представляющая собой всего лишь один длинный (но простой) case-оператор, в котором вам нужно делать множество мелких действий для множества разных случаев, можно использовать более длинную функцию.
Однако, если у вас есть сложная функция, и вы подозреваете, что менее одаренный первокурсник может даже не понимать, о чем эта функция, вам следует еще более строго придерживаться максимальных ограничений. Используйте вспомогательные функции с описательными именами (вы можете попросить компилятор встроить их (in-line), если считаете, что это критично для производительности, и он, вероятно, справится с этой задачей лучше, чем вы).
Другой мерой функции является количество локальных переменных. Их не должно быть больше 5-10, иначе вы что-то делаете не так. Переосмыслите функцию и разделите ее на более мелкие части. Человеческий мозг обычно может легко отслеживать около 7 разных вещей, если больше, то он запутается. Вы знаете, что вы гениальны, но, возможно, вы хотели бы понять, что вы сделали через 2 недели.
7. Комментирование
Комментарии — это хорошо, но существует опасность их чрезмерного комментирования. НИКОГДА не пытайтесь объяснить в комментарии, КАК работает ваш код: гораздо лучше написать код так, чтобы работа была очевидна, а объяснять плохо написанный код — пустая трата времени.
Как правило, вы хотите, чтобы ваши комментарии сообщали, ЧТО делает ваш код, а не КАК. Комментарий в рамке с описанием функции, возвращаемого значения и того, кто ее вызывает, помещается над телом — это хорошо. Кроме того, старайтесь избегать размещения комментариев внутри тела функции: если функция настолько сложна, что вам нужно отдельно комментировать ее части, вам, вероятно, следует еще раз перечитать раздел «Функции». Вы можете делать небольшие комментарии, чтобы отметить или предупредить о чем-то особенно умном (или некрасивом), но старайтесь избегать излишеств. Вместо этого поместите комментарии в начале функции, рассказывая людям, что она делает и, возможно, ПОЧЕМУ она это делает.
Если используются комментарии типа /* Fix me */, пожалуйста, скажите, почему что-то нужно исправить. Если в затронутую часть кода было внесено изменение, либо удалите комментарий, либо измените его, чтобы указать, что изменение было внесено и требует тестирования.
8. Скрипты оболочки и файлы Makefile
Не у всех установлены одинаковые инструменты и пакеты. Некоторые люди используют vi, другие emacs. Некоторые даже избегают установки любого пакета, предпочитая легкий текстовый редактор, такой как nano или встроенный в Midnight Commander.
gawk против mawk. Опять же, не у всех будет установлен gawk, mawk почти в десять раз меньше по размеру и при этом соответствует стандарту POSIX AWK. Если требуется какая-то непонятная команда, специфичная для gawk, которую mawk не предоставляет, то у некоторых пользователей скрипт не работает. То же самое относится и к mawk. Короче говоря, используйте общий вызов awk вместо gawk или mawk.
9. Соглашения С++
Обсуждение стилей программирования C++ всегда заканчиваются жаркими дебатами (что-то вроде споров между emacs и vi). Одно можно сказать наверняка: общий стиль, используемый всеми, кто работает над проектом, приводит к единообразному и удобочитаемому коду.
Соглашения об именах: константы из #define или enumerations должны быть в верхнем регистре. Обоснование: упрощает обнаружение констант в момент компиляции в исходном коде, например, EMC_MESSAGE_TYPE.
Classes и Namespaces должны использовать первую букву каждого слова с заглавной буквы и избегать подчеркивания. Обоснование: Идентифицируют classes, constructors и destructors, например, GtkWidget.
Методы (или имена функций) должны соответствовать приведенным выше рекомендациям C и не должны включать имя класса. Обоснование: поддерживает общий стиль для исходных кодов C и C++, например, get_foo_bar().
Однако логические методы легче читать, если они избегают символов подчеркивания и используют префикс «is» (не путать с методами, которые манипулируют логическими значениями). Обоснование: Идентифицирует возвращаемое значение как TRUE или FALSE и ничего больше, например, isOpen, isHomed.
НЕ используйте Not в логическом имени, это приводит только к путанице при выполнении логических тестов, например, isNotOnLimit или is_not_on_limit - это ПЛОХО.
В именах переменных следует избегать использования верхнего регистра и символов подчеркивания, за исключением локальных или частных имен. Следует по возможности избегать использования глобальных переменных. Обоснование: разъясняет, какие из них являются переменными, а какие методами. Общедоступный: например, axislimit Private: например, maxvelocity_ .
9.1. Конкретные соглашения об именовании методов
Термины get и set следует использовать там, где доступ к атрибуту осуществляется напрямую. Обоснование: указывает назначение функции или метода, например, get_foo set_bar.
Для методов, использующих логические атрибуты, предпочтительнее использовать set & reset. Обоснование: как указано выше. например set_amp_enable reset_amp_fault
Методы интенсивно использующие вычисления должны использовать compute в качестве префикса. Обоснование: показывает, что это требует больших вычислительных ресурсов и загружает ЦП. например compute_PID
По возможности следует избегать сокращений в именах. Исключение составляют имена локальных переменных. Обоснование: Ясность кода. например pointer предпочтительнее, чем ptr, compute предпочтительнее, чем cmp, compare снова предпочтительнее, чем cmp.
Enumerates и другие константы могут иметь префикс общего имени типа, например, enum COLOR { COLOR_RED, COLOR_BLUE };
.
Следует избегать чрезмерного использования макросов и определений. Предпочтительно использовать простые методы или функции. Обоснование: улучшает процесс отладки.
Файлы заголовков Include Statements должны быть включены в начало исходного файла, а не разбросаны по всему тексту. Они должны быть отсортированы и сгруппированы по их иерархическому положению в системе, при этом файлы низкого уровня должны включаться в первую очередь. Включаемые пути к файлам НИКОГДА не должны быть абсолютными. Вместо этого используйте флаг компилятора -I, чтобы расширить путь поиска. Обоснование: заголовки могут быть не в одном и том же месте во всех системах.
Указатели и ссылки должны иметь символ ссылки рядом с именем переменной, а не с именем типа. Обоснование: уменьшает путаницу, например, float *x
или int &i
.
Неявные проверки нуля не должны использоваться, за исключением булевых переменных, например, if (spindle_speed != 0)
НЕ if (spindle_speed)
.
В конструкцию for() должны быть включены только операторы управления циклом, например, sum = 0; for (i=0; i<10; i++) { sum += value[i]; }
НЕ: for (i=0, sum=0; i<10; i++) sum += value[i];
.
Точно так же следует избегать исполняемых операторов в условных операторах, например, if (fd = open(file_name)
неверный.
Следует избегать сложных условных операторов. Вместо этого используйте временные логические переменные.
Скобки должны использоваться в математических выражениях в большом количестве. Не полагайтесь на приоритет операторов, когда лишние скобки могут прояснить ситуацию.
Имена файлов: исходники и заголовки C++ используют расширения .cc и .hh. Использование .c и .h зарезервировано для простого C. Заголовки предназначены для объявлений классов, методов и структур, а не для кода (если только функции не объявлены встроенными).
10. Стандарты кодирования Python
Используйте стиль PEP 8 для кода Python.
11. Стандарты кодирования .comp
В части объявлений файла .comp каждое объявление начинается с первого столбца. Вставляйте дополнительные пустые строки, когда они помогают сгруппировать связанные элементы.
In the code portion of a .comp file, follow normal C coding style.