Гайд по оформлению кода на С++ от Стэнфордского университета


Оглавление (нажмите, чтобы открыть):

Требования
к оформлению программ на языке Си

© М.Л. Цымблер (mzym@susu.ru), Е.В. Аксенова (evaksen@mail.ru)

1. Соглашения по идентификаторам

1.1 Подбор идентификаторов

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

Неудачными можно считать идентификаторы:

1.1.2 Идентификаторы рекомендуется подбирать из слов английского языка. Например:

Не очень удачными можно считать идентификаторы:

1.2 Написание идентификаторов

1.2.1 Идентификаторы констант и макроопределений рекомендуется писать заглавными буквами. Например:

1.2.2 Существуют разные подходы к написанию остальных идентификаторов. Например:

а) все буквы идентификатора пишутся маленькими, для разделения слов в идентификаторе используется символ «_»

б) в идентификаторах каждое слово, входящее в идентификатор, писать, начиная с большой буквы, остальные буквы — маленькие.

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

Принятого подхода нужно придерживаться во всем тексте программы.

2. Соглашения по самодокументируемости программ

2.1 Комментарии

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

2.2 Спецификация функции и прототипа

Для каждой пользовательской функции должна быть описана в виде комментария спецификация, содержащая следующую информацию:
а) назначение функции;
б) описание семантики параметров-значений (параметров, передаваемых по значению), если она неочевидна;
в) описание семантики параметров-переменных (параметров, передаваемых по ссылке), если она неочевидна.
г) описание семантики возвращаемого значения, если она неочевидна.
Например:

1) семантика параметров и возвращаемого значения очевидна:

2) семантика параметров очевидна, семантика возвращаемого значения неочевидна

3) семантика параметров и возвращаемого значения неочевидна

Замечание:
Если функция реализует какой-либо вычислительный метод (например: нахождение площади фигуры методом трапеций, поиск минимума функции методом Ньютона и т.п.), рекомендуется в теле функции поместить комментарий с кратким описанием метода, либо ссылку на источник, где описан метод.

Прототипы функций достаточно снабдить кратким комментарием назначения функции. Например:

2.3 Спецификация программного файла

Программный файл должен начинаться со спецификации в виде комментария, содержащего следующую информацию:
а) идентификация (имя) файла;
б) фамилия и копирайт автора;
в) дата написания файла;
г) версия языка программирования и замечания по компиляции программного файла в других версиях языка (если требуется);
д) назначение программного файла;
Например:

3. Соглашения по читаемости программ

3.1 Лесенка

«Лесенка» должна отражать структурную вложенность языковых конструкций. Рекомендуется отступ не менее 2-х и не более 8-и пробелов. Принятого отступа нужно придерживаться во всем тексте программы. Правила написания конструкций (K&R стиль):

е) определение функции

3.2 Длина строк программного текста

Длина строк программы не должна превышать ширины экрана (80 символов). Инструкции длиннее 80 символов разбиваются на логические части, которые всегда значительно короче, чем изначальная строка, и распологаются со сдвигом вправо. То же самое относится к заголовкам функций с длинным списком аргументов и к длинным строковым константам. Например:

3.3 Прочие рекомендации

3.3.1 Рекомендуется при перечислении идентификаторов после запятой «,» ставить один пробел » «. Например:

3.3.2 Рекомендуется всегда писать символ-разделитель операторов «;» (непосредственно после оператора). Например:

Как стать программистом

Обучение основам программирования на C для чайников.

Страницы

Последние новости

YoungCoder теперь и на Stepikе. Записывайтесь: https://vk.cc/75rISy

Чтобы записаться на курс, необходимо зарегистрироваться на Степике: https://vk.cc/75rIC4

Это моя личная ссылка-приглашение на Stepik для вас. Регистрируясь по этой ссылке, записываясь на курсы и решая задачи, Вы помогаете автору данного сайта принять участие в конкурсе платформы Stepik! Подробности конкурса здесь: https://vk.cc/75rKuS

воскресенье, 27 ноября 2011 г.

Занятие 8.Оформление кода программы на Си.Уроки программирования для чайников.Язык Си.

>

Вам надо раз и навсегда определиться где вы будете ставить скобки и непременно следовать этому своему стилю. Каюсь, я и сам грешен, частенько используя второй стиль, перепрыгиваю на первый. Хотя смешивание это плохо. В ближайшее время, я постараюсь пройтись по всем листингам в блоге и привести оформление к единому образцу.
В качестве совета который я уже давал в комментариях. Всегда пишите фигурные скобки, даже если у вас один оператор в теле цикла, и в конструкции if. И при том сразу напишите заготовку if () <>, а потом уже записывайте условие и что делать при этом условии. Так же и с циклами.
Еще один совет, если у вас много вложенных друг в друга циклов и там еще вложены конструкции if, то очень удобно после закрывающей фигурной скобки писать к чему она относится например:
Листинг 8.3.

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

Как правильно оформлять программный код на C++

От переводчика. Искал в интернете простое и легко применимое руководство по оформлению программ на C++. Мне понравился один из вариантов, и я решил его перевести и опубликовать. — Dyzzet (https://habrahabr.ru/users/di_zed/, https://twitter.com/dyzzet).

Введение

Настоящий документ содержит рекомендации по написанию программ на языке C++.

Рекомендации основаны на установившихся стандартах, собранных из различных источников, личного опыта, частных требований и потребностей определённых проектов, а также почерпнутых из источников (см. ниже).

Но для появления ещё одного списка рекомендаций, помимо указанных источников, есть несколько причин. Основная причина — их излишняя обобщённость, поскольку зачастую требуется задать частные правила (в особенности правила именования). Данный документ содержит комментарии, что делает его более удобным в использовании при проведении ревизий кода, чем другие уже существующие документы. К тому же, рекомендации по программированию обычно вперемешку содержат описания проблем стиля и технических проблем, что не совсем удобно. Этот документ не содержит каких-либо технических рекомендаций по C++, делая упор на вопросах стиля.

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

Формат документа

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

Рекомендации отображаются следующим образом:

n. Короткое описание рекомендации.

Комментарии к рекомендациям особенно важны, поскольку стандарты написания кода и гайдлайны обычно разжигают «холивары», и важным моментом является объяснение рекомендации.

Важность рекомендаций

Рекомендации разделены по степени важности: обязательные, настоятельно рекомендуемые и общие.

Общие рекомендации

1. Допускаются любые нарушения рекомендаций, если это улучшает читаемость.

Основная цель рекомендаций — улучшение читаемости и, следовательно, ясности и лёгкости поддержки, а также общего качества кода. Невозможно дать рекомендации на все случаи жизни, поэтому программист должен мыслить гибко.

2. Правила могут быть нарушены, если против них есть персональные возражения.

Это попытка создать набор общих рекомендаций, не навязывая всем единый стиль. Опытные программисты обычно всё равно подгоняют стиль под себя. Подобный список рекомендаций, имеющийся под рукой (или хотя бы требование ознакомиться с ним), обычно заставляет людей задумываться о стиле программирования и оценке их собственных практик в этой области.

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

Соглашения об именовании

3.1 Общие соглашения об именовании

3. Имена, представляющие типы, должны быть обязательно написаны в смешанном регистре, начиная с верхнего.

Общая практика в сообществе разработчиков C++.

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

Общая практика в сообществе разработчиков C++. Позволяет легко отличать переменные от типов, предотвращает потенциальные коллизии имён, например: Line line;

5. Именованные константы (включая значения перечислений) должны быть записаны в верхнем регистре с нижним подчёркиванием в качестве разделителя.

Общая практика в сообществе разработчиков C++. Использование таких констант должно быть сведено к минимуму. В большинстве случаев реализация значения в виде метода — лучшее решение:

Эта форма более читаемая и гарантирует единый интерфейс к значениям, хранящимся в классе.

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

Совпадает с правилом для переменных, но отличие между ними состоит в их специфических формах.

7. Названия пространств имён следует записывать в нижнем регистре.

Общая практика в сообществе разработчиков C++.

8. Следует называть имена типов в шаблонах одной заглавной буквой.

Общая практика в сообществе разработчиков C++. Позволяет выделить имена шаблонов среди других используемых имён.

9. Аббревиатуры и сокращения в именах должны записываться в нижнем регистре.

Использование верхнего регистра может привести к конфликту имён, описанному выше. Иначе переменные бы имели имена dVD, hTML и т. д., что не является удобочитаемым. Другая проблема уже описана выше; когда имя связано с другим, читаемость снижается; слово, следующее за аббревиатурой, не выделяется так, как следовало бы.

10. Глобальные переменные всегда следует использовать с оператором разрешения области видимости (::).

Следует избегать использования глобальных переменных. Предпочтительнее использование синглтонов.

11. Членам класса с модификатором private следует присваивать суффикс-подчёркивание.

Не считая имени и типа, область видимости — наиболее важное свойство переменной. Явное указание модификатора доступа в виде подчёркивания избавляет от путаницы между членами класса и локальными переменными. Это важно, поскольку переменные класса имеют большее значение, нежели переменные в методах, и к ним следует относиться более осторожно.

Дополнительным эффектом от суффикса-подчёркивания является разрешение проблемы именования в методах, устанавливающих значения, а также в конструкторах:

Проблема заключается в том, что существует два варианта подчёркивания — в виде суффикса и в виде префикса. Оба варианта широко используются, но рекомендуется именно первый вариант, потому что он обеспечивает лучшую читаемость. Следует отметить, что определение модификатора доступа у переменных — иногда спорный вопрос. Хотя кажется, что рекомендуемая практика набирает сторонников и становится всё более распространённой в среде профессионалов.

12. Настраиваемым переменным следует давать то же имя, что и у их типа.

void setTopic(Topic* topic) // НЕЛЬЗЯ: void setTopic(Topic* value)
// НЕЛЬЗЯ: void setTopic(Topic* aTopic)
// НЕЛЬЗЯ: void setTopic(Topic* t)

void connect(Database* database) // НЕЛЬЗЯ: void connect(Database* db)
// НЕЛЬЗЯ: void connect (Database* oracleDB)

Сокращайте сложность путём уменьшения числа используемых терминов и имён. Также упрощает распознавание типа просто по имени переменной.

Если по какой-то причине эта рекомендация кажется неподходщей, это означает, что имя типа выбрано неверно.

Не являющиеся настраиваемыми переменные могут быть названы по их назначению и типу:

13. Все имена следует записывать по-английски.

Английский наиболее предпочителен для интернациональной разработки.

14. Переменные, имеющие большую область видимости, следует называть длинными именами, имеющие небольшую область видимости — короткими.

Имена временных переменных, использующихся для хранения временных значений или индексов, лучше всего делать короткими. Программист, читающий такие переменные, должен иметь возможность предположить, что их значения не используются за пределами нескольких строк кода. Обычно это переменные i, j, k, l, m, n (для целых), а также c и d (для символов).

15. Имена объектов не указываются явно, следует избегать указания названий объектов в именах методов.

Второй вариант смотрится вполне естественно в объявлении класса, но совершенно избыточен при использовании, как это и показано в примере.

(Пункт № 16 отсутствует.— Примечание переводчика.)

3.2 Особые правила именования

17. Слова get/set должны быть использованы везде, где осуществляется прямой доступ к атрибуту.

matrix.getElement(2, 4);
matrix.setElement(2, 4, value);

Общая практика в сообществе разработчиков C++. В Java это соглашение стало более-менее стандартным.

18. Слово compute может быть использовано в методах, вычисляющих что-либо.

Дайте читающему сразу понять, что это времязатратная операция.

19. Слово find может быть использовано в методах, осуществляющих какой-либо поиск.

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

20. Слово initialize может быть использовано там, где объект или сущность инициализируется.

Следует отдавать предпочтение американскому варианту initialize, нежели британскому initialise. Следует избегать сокращения init.

21. Переменным, представляющим GUI, следует давать суффикс, соответствующий имени типа компонента.

Улучшает читаемость, поскольку имя даёт пользователю прямую подсказку о типе переменной и, следовательно, ресурсах объектов.

22. Множественное число следует использовать для представления наборов (коллекций) объектов.

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

23. Префикс n следует использовать для представления числа объектов.

Обозначение взято из математики, где оно является установившимся соглашением для обозначения числа объектов.

24. Суффикс No следует использовать для обозначения номера сущности.

Обозначение взято из математики, где оно является установившимся соглашением для обозначения номера сущности.

Другой неплохой альтернативой является префикс i: iTable, iEmployee. Он ясно даёт понять, что перед нами именованный итератор.

25. Переменным-итераторам следует давать имена i, j, k и т. д.

Обозначение взято из математики, где оно является установившимся соглашением для обозначения итераторов.

Переменные с именами j, k и т. д. рекомендуется использовать только во вложенных циклах.

26. Префикс is следует использовать только для булевых (логических) переменных и методов.

Использование этого префикса избавляет от таких имён, как status или flag. isStatus или isFlag просто не подходят, и программист вынужден выбирать более осмысленные имена.

В некоторых ситуациях префикс is лучше заменить на другой: has, can или should:

27. Симметричные имена должны использоваться для соответствующих операций.

Уменьшайте сложность за счёт симметрии.

28. Следует избегать сокращений в именах.

Рассмотрим два вида слов. Первые — обычные слова, перечисляемые в словарях, которые нельзя сокращать. Никогда не сокращайте:

Второй вид — слова, специфичные для какой-либо области, которые известны по своему сокращению/аббревиатуре. Их следует записывать сокращённо. Никогда не пишите:

29. Следует избегать дополнительного именования указателей.

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

30. Нельзя давать булевым (логическим) переменным имена, содержащие отрицание.

Проблема возникает, когда такое имя используется в конъюнкции с оператором логического отрицания, что влечёт двойное отрицание. Результат не обязательно будет отрицанием !isNotFound.

31. Константы в перечислениях могут иметь префикс — общее имя типа.

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

Другим подходом является обращение к константам по их общему типу: Color::RED, Airline::AIR_FRANCE и т. д.

Обратите внимание, что имя перечисления обычно записано в единственном числе, например: enum Color <. >. Имя во множественном числе хорошо выглядит при объявлении, но не очень хорошо подходит для практического использования.

32. Классам исключений следует присваивать суффикс Exception.

Классы исключений в действительности не являются частью архитектуры программ, и такое именование отделяет их от других классов.

33. Функциям (методам, возвращающим какие-либо значения) следует давать имена в зависимости от того, что они возвращают, а процедурам — в зависимости от того, что они выполняют (методы void).

Улучшайте читаемость. Такое именование даёт понять, что метод делает, а что нет, а также избавляет код от потенциальных побочных эффектов.

4 Файлы

4.1 Файлы исходных кодов

34. Заголовочным файлам C++ следует давать расширение .h (предпочтительно) либо .hpp. Файлы исходных кодов могут иметь расширения .c++ (рекомендуется), .C, .cc либо .cpp.

Это расширения, одобряемые стандартом C++.

35. Класс следует объявлять в заголовочном файле и определять (реализовывать) в файле исходного кода, имена файлов совпадают с именем класса.

Облегчает поиск связанных с классом файлов. Очевидное исключение — шаблонные классы, которые должны быть объявлены и определены в заголовочном файле.

36. Все определения должны находиться в файлах исходного кода.

Заголовочные файлы объявляют интерфейс, файлы исходного кода его реализовывают. Если программисту необходимо найти реализацию, он должен быть уверен, что найдёт её именно в файле исходного кода.

37. Содержимое файлов не должно превышать 80 колонок.

80 колонок — широко распространённое разрешение для редакторов, эмуляторов терминалов, принтеров и отладчиков; файлы передаются между различными людьми, поэтому нужно придерживаться этих ограничений. Уместная разбивка строк улучшает читаемость при совместной работе над исходным кодом.

38. Нельзя использовать специальные символы (например, TAB) и разрывы страниц.

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

39. Незавершённость разбитых строк должна быть очевидна.

totalSum = a + b + c +
d + e;

function (param1, param2,
param3);

setText («Long line split»
«into two parts.»);

for (int tableNo = 0; tableNo

Разбивка строк появляется, когда ограничение на 80 колонок, описанное выше, нарушается. Сложно дать жёсткие правила по разбивке, но примеры выше показывают общие принципы.

  • разрыв после запятой;
  • разрыв после оператора;
  • выравнивание новой строки с началом выражения на предыдущей строке.

4.2 Включения файлов

40. Заголовочные файлы должны содержать защиту от вложенного включения.

Конструкция позволяет избегать ошибок компиляции. Это соглашение позволяет увидеть положение файла в структуре проекта и предотвращает конфликты имён.

41. Директивы включения следует сортировать (по месту в иерархии системы, ниже уровень — выше позиция) и группировать. Оставляйте пустую строку между группами.

#include «com/company/ui/PropertiesDialog.h»
#include «com/company/ui/MainWindow.h»

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

42. Директивы включения должны располагаться только в начале файла.

Общая практика. Избегайте нежелательных побочных эффектов, которые может вызвать «скрытое» включение где-то в середине файла исходного кода.

5 Выражения

5.1 Типы

43. Локальные типы, используемые в одном файле, должны быть объявлены только в нём.

Улучшает сокрытие информации.

44. Разделы класса public, protected и private должны быть отсортированы. Все разделы должны быть явно указаны.

Сперва должен идти раздел public, что избавит желающих ознакомиться с классом от чтения разделов protected/private.

45. Приведение типов должно быть явным. Никогда не полагайтесь на неявное приведение типов.

Этим программист показывает, что ему известно о различии типов, что смешение сделано намеренно.

5.2 Переменные

46. Следует инициализировать переменные в месте их объявления.

Это даёт гарантию, что переменные пригодны для использования в любой момент времени. Но иногда нет возможности осуществить это:

В этих случаях лучше оставить переменные неинициализированными, чем присваивать им какие-либо значения.

47. Переменные никогда не должны иметь двойной смысл.

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

48. Следует избегать использования глобальных переменных.

Не существует причины использовать глобальные переменные в C++ (на самом деле существует.— Примечание переводчика). То же касается глобальных функций и (статических) переменных, область видимости которых — весь файл.

49. Не следует объявлять переменные класса как public.

Эти переменные нарушают принципы сокрытия информации и инкапсуляции. Вместо этого используйте переменные с модификатором private и соответствующие функции доступа. Исключение — класс без поведения, практически структура данных (эквивалент структур языка C). В этом случае нет смысла скрывать эти переменные.

Обратите внимание, что структуры в языке C++ оставлены только для совместимости с C; их использование ухудшает читаемость кода. Вместо структур используйте классы.

(Пункт № 50 отсутствует.— Примечание переводчика.)

51. Символ указателя или ссылки в языке C++ следует ставить сразу после имени типа, а не с именем переменной.

То, что переменная — указатель или ссылка, относится скорее к её типу, а не к имени. Программисты на C часто используют другой подход, но в C++ лучше придерживаться этой рекомендации.

(Пункт № 52 отсутствует.— Примечание переводчика.)

53. Следует избегать неявного сравнения булевых (логических) переменных и указателей с нулём.

Стандарт C++ не гарантирует, что значения переменных int и float, равные нулю, будут представлены как бинарный 0. Также при явном сравнении видно сравниваемый тип.

Логично было бы предположить, что также и указатели не следует неявно сравнивать с нулём, например, if (line == 0) вместо if (line). Последнее является очень распространённой практикой в C/C++, поэтому также может быть использовано.

54. Переменные следует объявлять в как можно меньшей области видимости.

Это упрощает контроль над действием переменной и сторонними эффектами.

5.3 Циклы

55. Нельзя включать в конструкцию for() выражения, не относящиеся к управлению циклом.

Улучшайте поддержку и читаемость. Строго разделяйте контроль над циклом и то, что в нём содержится.

56. Переменные, относящиеся к циклу, следует инициализировать непосредственно перед ним.

57. Можно избегать циклов do-while.

Такие циклы хуже читаемы, поскольку условие описано после тела. Читающему придётся просмотреть весь цикл, чтобы понять его работу.

Циклы do-while вообще не являются острой необходимостью. Любой такой цикл может быть заменён на цикл while или for.

Меньшее число используемых конструкций улучшает читаемость.

58. Следует избегать использования break и continue в циклах.

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

(Пункт № 59 отсутствует.— Примечание переводчика.)

60. Для бесконечных циклов следует использовать форму while (true) .

Проверка на единицу не является необходимой и бессмысленна. Форма for (;;) не очень читаема; также не является очевидным, что цикл бесконечный.

5.4 Условные выражения

61. Строго избегайте сложных уловных выражений. Вместо этого вводите булевы переменные.

bool isFinished = (elementNo maxElement);
bool isRepeatedEntry = elementNo == lastElement;
if (isFinished || isRepeatedEntry) <
:
>

// NOT:
if ((elementNo maxElement)||
elementNo == lastElement) <
:
>

Задание булевых переменных для выражений приведёт к самодокументированию программы. Конструкцию будет легче читать, отлаживать и поддерживать.

62. Ожидаемую часть следует располагать в части if, исключение — в части else.

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

63. Условие следует размещать в отдельной строке.

Применяется для отладки.

64. Следует строго избегать исполнимых выражений в условиях.

File* fileHandle = open(fileName, «w»);
if (!fileHandle) <
:
>

Исполняемые выражения в условиях усложняют читаемость. Особенно это касается новичков в С/С++.

5.5 Разное

65. Следует избегать «магических» чисел в коде. Числа, отличные от 0 или 1, следует объявлять как именованные константы.

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

66. Константы с плавающей точкой следует записывать с десятичной точкой и с указанием по крайней мере одной цифры после запятой.

double total = 0.0; // НЕ РЕКОМЕНДУЕТСЯ: double total = 0;
double speed = 3.0e8; // НЕ РЕКОМЕНДУЕТСЯ: double speed = 3e8;

double sum;
:
sum = (a + b) * 10.0;

Это подчёркивает различные подходы при работе с целыми числами и числами с плавающей точкой. С точки зрения математики, эти две модели совершенно различны и не совместимы.

А также (как это показано в последнем примере выше) делается акцент на типе переменной (sum) в том месте, где это не является очевидным.

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

Система чисел и выражений в C++ заимствована из математики, и следует придерживаться традиционных форм записи, где это возможно. Помимо прочего, 0.5 — более читаемо, чем .5 (первый вариант никак не спутать с числом 5).

68. У функций нужно обязательно указывать тип возвращаемого значения.

Если это не указано явно, C++ считает, что возвращаемое значение имеет тип int. Никогда нельзя полагаться на это, поскольку такой способ может смутить программистов, не знакомых с ним.

69. Не следует использовать goto.

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

70. Следует использовать «0» вместо «NULL».

NULL является частью стандартной библиотеки C и устарело в C++.

6 Оформление и комментарии

6.1 Оформление

71. Основной отступ следует делать в два пробела.

Отступ в один пробел достаточно мал, чтобы отражать логическую структуру кода. Отступ более 4 пробелов делает глубоко вложенный код нечитаемым и увеличивает вероятность того, что строки придётся разбивать. Широко распространены варианты в 2, 3 или 4 пробела; причём 2 и 4 — более широко.

72. Блоки кода следует оформлять так, как показано в примере 1 (рекомендуется) или в примере 2, но ни в коем случае не так, как показано в примере 3. Оформление функций и классов должно следовать примеру 2.

while (!done) <
doSomething();
done = moreToDo();
>

while (!done)
<
doSomething();
done = moreToDo();
>

while (!done)
<
doSomething();
done = moreToDo();
>

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

73. Объявления классов следует оформлять следующим образом:

class SomeClass : public BaseClass
<
public:
.

Частное следствие из правила, указанного выше.

74. Определения методов следует оформлять следующим образом:

Следствие из правила, указанного выше.

75. Конструкцию if-else следует оформлять следующим образом:

if (condition) <
statements;
>

if (condition) <
statements;
>
else <
statements;
>

if (condition) <
statements;
>
else if (condition) <
statements;
>
else <
statements;
>

Следствие из правила, указанного выше. Причём написание else на той же строке, где стоит закрывающая фигурная скобка первого блока, не является запрещённым:

Лучше каждую часть if-else помещать на отдельной строке. Это упрощает действия с кодом, например, перемещение блока else.

76. Цикл for следует оформлять следующим образом:

Следствие из правила, указанного выше.

77. Цикл for с пустым телом следует оформлять следующим образом:

Делает акцент для читающего на том, что тело пусто. Однако циклов, не имеющих тела, следует избегать.

78. Цикл while следует оформлять следующим образом:

Следствие из правила, указанного выше.

79. Цикл do-while следует оформлять следующим образом:

Следствие из правила, указанного выше.

80. Конструкцию switch следует оформлять следующим образом:

switch (condition) <
case ABC :
statements;
// Отсутствует «break»

case DEF :
statements;
break;

case XYZ :
statements;
break;

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

81. Конструкцию try-catch следует оформлять следующим образом:

Следствие из правила, указанного выше. Вопросы, касающиеся закрывающих фигурных скобок у конструкции if-else, применимы и здесь.

82. Если конструкция if-else содержит только одно выражение в теле, фигурные скобки можно опускать.

if (condition)
statement;

while (condition)
statement;

for (initialization; condition; update)
statement;

Рекомендуется всё же не опускать фигурные скобки.

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

Так функции выровнены в одну колонку.

6.2 Пробелы

84. Пробелы

  • Операторы следует отбивать пробелами.
  • После зарезервированных ключевых слов языка C++ следует ставить пробел.
  • После запятых следует ставить пробелы.
  • Двоеточия следует отбивать пробелами.
  • После точек с запятой в цикле for следует ставить пробелы.

a = (b + c) * d; // НЕ РЕКОМЕНДУЕТСЯ: a=(b+c)*d

while (true) // НЕ РЕКОМЕНДУЕТСЯ: while(true)
<
.

doSomething(a, b, c, d); // НЕ РЕКОМЕНДУЕТСЯ: doSomething(a,b,c,d);

case 100 : // НЕ РЕКОМЕНДУЕТСЯ: case 100:

Выделяет отдельные части выражений. Улучшает читаемость. Сложно дать всеобъемлющий набор рекомендаций относительно пробелов в языке C++. Рекомендации выше должны показать общие принципы.

85. После имён методов может идти пробел, если далее следует другое имя.

Выделяет отдельные имена. Улучшает читаемость. Если далее нет никакого имени, пробел можно опускать (doSomething()).

Другим подходом является указание пробела сразу после открывающей скобки. Использующие его также обычно ставят пробел и перед закрывающей скобкой: doSomething( currentFile );. Это позволяет выделять отдельные имена; пробел перед закрывающей скобкой выглядит неестественно, но без него выражение выглядит несимметрично (doSomething( currentFile);).

86. Логические блоки в коде следует отделять пустой строкой.

Matrix4x4 matrix = new Matrix4x4();

double cosAngle = Math.cos(angle);
double sinAngle = Math.sin(angle);

matrix.setElement(1, 1, cosAngle);
matrix.setElement(1, 2, sinAngle);
matrix.setElement(2, 1, -sinAngle);
matrix.setElement(2, 2, cosAngle);

87. Методы рекомендуется отделять тремя пустыми строками.

Это позволяет лучше их выделять.

88. Переменные в объявлениях можно выравнивать.

Улучшает читаемость. Чётче видны пары тип — переменная.

89. Используйте выравнивание везде, где это улучшает читаемость.

if (a == lowValue) compueSomething();
else if (a == mediumValue) computeSomethingElse();
else if (a == highValue) computeSomethingElseYet();

value = (potential * oilDensity) / constant1 +
(depth * waterDensity) / constant2 +
(zCoordinateValue * gasDensity) / constant3;

minPosition = computeDistance(min, x, y, z);
averagePosition = computeDistance(average, x, y, z);

switch (value) <
case PHASE_OIL : strcpy(phase, «Oil»); break;
case PHASE_WATER : strcpy(phase, «Water»); break;
case PHASE_GAS : strcpy(phase, «Gas»); break;
>

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

6.3 Комментарии

90. Сложный код, написанный с использованием хитрых ходов, следует не комментировать, а переписывать!

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

91. Все комментарии следует писать на английском.

В интернациональной среде английский — предпочтительный язык.

92. Используйте // для всех комментариев, включая многострочные.

Если следовать этой рекомендации, многострочные комментарии /* */ можно использовать для отладки и иных целей.

После // следует ставить пробел, а сам комментарий следует начинать писать с большой буквы завершать точкой.

93. Комментарии следует располагать так, чтобы они относились к тому, что они описывают.

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

94. Комментарии к классам и заголовкам методов следует делать в соответствии с соглашениями JavaDoc.

Программисты на языке Java используют более развитый подход к документированию благодаря стандартному автоматическому средству Javadoc, которое является частью пакета разработки и позволяет автоматически создавать документацию в формате HTML из комментариев в коде.

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

Теория чистого кода. Стиль кодирования

Чистый код должен быть эффективным, простым для восприятия и сопровождения, гибким и надежным. Приведенные требования зачастую противоречат друг другу, поэтому для написания чистого кода в каждом конкретном случае надо идти на некоторый компромисс. Нередко опытные программисты пытаются сформулировать советы по написанию чистого кода [1, 2, 3, 4, 5], которые зависят от используемого языка программирования, но во многом сходятся.

Эта статья изначально планировалась как своеобразная критика книги «Чистый код. Создание, анализ и рефакторинг» Роберта Мартина [1], поэтому я часто буду на него ссылаться. Мартин писал наиболее общие советы безотносительно конкретного языка программирования — этим его книга в корне отличается от других [2, 3, 4].

Статья не является сборником готовых инструкций к написанию кода, но должна наводить на мысль о том, как делать это более правильно.

Содержание:

Эволюция требований к чистому коду

Требования к коду менялись со временем. Очевидно, что в 80х годах компьютеры были менее производительны чем сейчас и огромный упор делался на эффективность программ. Рост производительности привел к появлению новых синтаксических конструкций, подходов к программированию и языкам. Так например, использование кодов ошибок вместо исключений в настоящее время считается дурным тоном, однако на заре компьютерной эры исключений просто не существовало.

Однако, изменение требований связано не только с ростом производительности — например, ограничение на ширину и высоту кода стали неактуальны с распространением мониторов с высоким разрешением. На старых мониторах строки, длина которых была более 80 символов, приходилось перематывать — это сильно осложняло чтение кода. Помимо ограничения на ширину, существовало также ограничение высоты функций — очень удобно если функция целиком умещается на один экран монитора. Сейчас эти требования не исчезли совсем, но стали более мягкими — писать весь код в одну строку не стоит.

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

Наконец, изменились средства разработки программ — появились системы контроля версий, удобные инструменты тестирования, системы отслеживания ошибок, управления задачами и многое другое. Весь этот инструментарий оказался интегрирован в удобные среды разработки.

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

  • не должен мешать программисту вносить изменения;
  • должен легко тестироваться;
  • должны использоваться, по возможности, стандартные решения.

Соглашения о кодировании

В каждой конторе существуют свои собственные соглашения о стиле кодирования (coding conventions). Когда я устроился на свою первую работу — мне тоже выдали такой документ, который представлял собой сборник правил. Было не понятно чем обусловлены эти правила, но в будущем я узнал, что основная их часть имеет под собой крепкое основание.

Например в соглашении было регламентировано именование файлов с исходным кодом, которое, среди прочего, запрещало использование строчных букв. Правило может выглядеть причудливо, де тех пор, пока его нарушение не приведет к тому, что код будет отлично работать в Windows, но откажется собираться в Linux. Связано это с тем, что по умолчанию Linux учитывает регистр в именах файлов, а Windows — нет.

В соглашении обычно фиксируется использование множества специфичных для конкретного языка программирования конструкций. Например, для языка С++ может быть закреплено обязательное использование ключевого слова const везде где это возможно (это позволяет переносить обнаружение ряда ошибок на этап компиляции), запрет использования директив pragma (они могут оказать негативное влияние на переносимость программ) или, например, требование использовать, по возможности, const вместо define.

Отступы

Большое внимание в соглашениях уделяется расстановке скобок, пробелов и переводов строк и т.п.. Казалось бы, нет разницы — поставлен пробел перед фигурной скобкой или нет, однако все эти правила стремятся обеспечить:

  • Единый стиль оформления кода во всем проекте;
  • Визуальное выделение наиболее значимых частей.

Может получиться так, что участники проекта привыкли использовать разные соглашения о кодировании – все они могут быть очень хорошими, но их смешанное использование даст плохой результат. Код просто будет почти также плохо читаться, как если бы его вообще не форматировали.

В качестве примера я взял первую попавшуюся студенческую поделку — решаемая задача стоит в том, чтобы заполнить массив случайными числами, а затем обработать его элементы по заданной формуле:

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

Смещение тела цикла (7-11 строки) произошло, вероятно, в следствии модификации кода — изначально это был вложенный цикл, но затем студент что-то исправил, но форматирование сохранил. В маленькой функции такое отсутствие форматирования не сильно мешает, но в более серьезном коде, оно отвлекает, расходует ваше время и портит зрение. В конце концов, многие IDE имеют горячие клавиши, для форматирования фрагмента кода по заранее заданным правилам — достаточно один раз настроить среду разработки чтобы всегда экономить время.

В приведенном коде есть множество других недочетов:

  • в 9 строке выполняется приведение типа в функциональном стиле (тип используется как функция) и после открывающей скобки стоит пробел, но в 14 строке — при вызове функции pow, пробел не поставлен. Возможно, автор лишний пробел поставил умышленно и человек, читающий код, обратит на это внимание;
  • лишний пробел стоит перед объявлением переменных в третьей строке;
  • оператор присваивания в 9 строке выделен пробелами, но в 10 — пробелы отсутствуют.

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

В приведенной программе стоит множество лишних круглых скобок, которые очень сильно осложняют восприятие. Мало того, что скобки очень важны и часто таят в себе ошибки, они имеют свойство скапливаться — как в 14 строке. Большинство сред разработки подсвечивают парные скобки, но это не очень сильно облегчает жизнь.

Общее правило состоит в том, чтобы не ставить скобки там, где они не нужны, при этом надо учитывать, что иногда лишние скобки надо оставить, т.к. далеко не все помнят в совершенстве приоритеты операций. В ряде случаев приоритеты можно показать пробелами (см. ниже).

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

Используя вертикальное форматирование, мы выделяем объявление переменных, цикл заполнения массива случайными числами и цикл обработки по формуле. Если ваша функция выполняет несколько действий — то разумно разделить соответствующие блоки кода пустыми строками.

Приведенная программа все еще далека от совершенства. Возможно, открывающие фигурные скобки не стоило выносить на отдельную строку, а между ключевым словом for и открывающей круглой скобкой нужно поставить пробел. Такие вопросы связаны с конкретным языком программирования и являются скорее религиозными, чем техническими — поэтому я не уделю им внимания. Однако, нельзя не заметить «плохие» имена переменных.

Имена

Коротко и ясно ключевое правило именования сформулировал Мартин — «имя должно отражать намерения программиста«, большинство других советов вытекает из этого утверждения: имя не должно дезинформировать, содержать лишнее, отвлекать, …. Достаточно часто пишут про недопустимость каламбуров и шуток в именах, а в моей педагогической деятельности был случай:

Студентка решала задачу о вычислении суммы ряда, при этом накопитель суммы назвала «i», а счетчики циклов — «s» и «o». На вопрос о том, почему она так назвала переменные, она ответила, что все ее одногруппники называют счетчики «i», а сумму — « или «sum» — поэтому это серые, унылые имена, а ей хочется писать красивые программы с гламурными именами.

Имена «i», «j» зарезервированы для счетчиков, от них не ожидают другого поведения. Имя «s» логично использовать для накопления суммы, а имя «o» — вообще лучше не использовать (визуально оно плохо отличимо от ноля).

Одно время мне приходилось использовать WinAPI, изобилующее всевозможными префиксами — разработчики Windows использовали Венгерскую нотацию, согласной которой тип своеобразным образом кодируется в имени [6].

В приведенном примере имена аргументов содержат закодированную информацию о типе. Так, префикс lp означает long pointer, префикс dwdouble word (два машинных слова — unsigned long), а префикс b кодирует логический тип данных.

В настоящее время Венгерская нотация не в моде, причиной тому стала эволюция средств разработки. Сейчас программисту достаточно написать имя функции, чтобы IDE подсказала типы аргументов, при наведении указателя мыши (или каретки) на переменную может высвечиваться ее тип. С другой стороны, использование Венгерской нотации — это очень утомительно, мало того, что надо помнить все префиксы и печатать кучу лишних букв, так еще феерические проблемы подстерегают при изменении типа переменной.

Тем не менее, частично такие нотации до сих пор применяются — например, я нахожу удобным дополнять имя областью видимости. Соглашение о стиле кодирования Google [7] предлагает в конце имени данных-членов класса ставить символ подчеркивания. Согласно правилам кодирования mozilla [8] различные префиксы присваиваются данным-членам, глобальным переменным, аргументам функций, статическим членам и константам.

Мартин считает что и такие префиксы не нужны, его мнение разделяют многие программисты — на habrahabr не однократно проводились опросы о соглашениях кодирования и префиксах [9], которые это подтверждают. Например, вместо префикса, выделяющего данные-члены класса (часто это m, m_ или символ подчеркивания), предлагается использовать указатель на текущий объект — this (это не пройдет в списке инициализации конструктора):

Кроме префиксов областей видимости есть и другие, например:

  • имена абстрактных классов (интерфейсов) дополняются префиксом I (ISocket), напротив — классы реализации могут снабжаться постфиксом Imp (SocketImp) или Impl (при использовании идиомы Pimpl). Класс в составе иерархии может содержать префикс C (CFigure), а классы исключений — постфикс Exception (BadArgumentsException)[1, 2, 10]. Есть множество других вариантов, которые часто противоречат друг другу.
  • имена функций дополняются префиксами:
    • is_ — проверяет что-то и возвращает логический тип — is_digit;
    • has_ — выполняет поиск какого-либо значения в контейнере — has_primeNumber;
    • get_ и set_ — метод возвращает или устанавливает значение какого-либо поля — set_volume, set_volume;
  • используются схемы именования, позволяющие различать объекты и типы данных — имена пользовательских типов предлагают начинать с заглавной буквы, а имена объектов — со строчной.

Правила именования не ограничиваются префиксами, например:

  • названия должны использовать по возможности слова из предметной области решаемой задачи;
  • имена классов должны выражаться существительными, функций и методов — глаголами;
  • имена классов должны быть хорошо различимы — Страуструп приводит пример с именами fl, f1, fI и fi [11].

Важно соблюдение одних и тех же правила всеми разработчиками проекта, в противном случае проблем не избежать. Например, один программист может захотеть писать имена всех констант заглавными буквами, а другой — выводить заглавными только макросы, в то время, как константы будет выделять заглавной буквой в начале и «верблюжьим регистром«.

Приведен утрированный пример, однако, в файле pr.cpp окажутся как константы, объявленные первым программистом, так и вторым. Различия в обозначениях будут мешать обоим программистам — один может думать, что FIVE — это макрос, другой не сразу поймет, что TripleWaterPointTemp является константой.

Комментарии

Комментарий в программировании — это некомпилируемая часть исходного кода, поясняющая принцип работы программы. Иногда в комментариях фиксируют, также, информацию:

  • о версии кода и, внесенных в ней, изменениях;
  • об авторе кода или конкретных правок,
  • о лицензии, по которой распространяется код;
  • о неисправленных ошибках и прочих недочетах, заметки разного рода.

От комментариев, несущих информацию об авторском праве и лицензии никуда не деться, однако с остальными можно бороться — в последнее время все шире распространяется мнение, о том, что «комментарии — признак плохого кода» [12, 13]. Впрочем, есть и другое мнение — так, например, соглашение о кодировании mozilla требует использовать комментарии в стиле JavaDoc [8], а Мейерс в одном из своих 55 советов упоминает doxygen [2].

Существуют разногласия, однако, все программисты сходятся на том, что:

  • комментарии должны говорить правду о коде. Корень зла — изменение кода, ведь параллельно надо менять комментарии. Слишком часто комментарии не изменяются, ведь начальство требует чтобы вы сдали проект вчера, а изменение комментариев в некоторых случаях занимает гораздо больше времени, чем сама правка кода;
  • комментарии не должны пояснять очевидные моменты, т.к. читать в любом случае приходится и код, и комментарии — это отнимает время;
  • комментарии должны быть понятны всем, а не только тем, кто их пишет;
  • комментарии не должны содержать мусора и размышлений автора о жизни;
  • написание комментариев и поддержка единого стиля комментариев не должна отнимать слишком много времени.

Из этого понятно, что комментарий должен быть точным, коротким и по теме. Комментариев следует избегать — по возможности стоит переписать код так понятно, чтобы потребность в комментарии пропала вовсе. Использование современных инструментов разработки позволяют полностью исключить некоторые типы комментариев из программы:

  • информацию о версии программы, авторе изменений и ее особенностях позволяют хранить системы управления версиями [14 , 15];
  • комментарии TODO, BUG и FIXME могут быть перенесены в трекеры задач и ошибок.

В информации, связанной с описанием ошибки или версии программы обычно указывается дата время и автор изменений — специализированные системы делают это автоматически в едином формате. Кроме того, такие системы управляют доступом к задачам (могут как сделать информацию общедоступной, так и доступной узкому кругу лиц) и позволяют распределять задачи и изменять их статус. Очевидно, что использование специализированных инструментов предпочтительнее.

Несмотря на то, что современные среды разработки умеют обрабатывать и выводить в окошках информацию о TODO, FIXME, NOTE и прочих специальных комментариях, могут существовать различия в формате:

Различные IDE могут как среагировать на оба комментария, так и ни на один из них :). В данном случае проблему создал один лишний пробел — в конторе где я работал с этим столкнулись, когда начали переносить проект с Windows (использовали Microsoft Visual Studio) на Linux (в качестве IDE выбрали Qt Creator).

Комментарии часто дублируют код — когда код понятен без комментариев. Особенно хорошо это видно при написании комментариев для doxygen или javadoc. Системы типа doxygen позволяют строить документацию к программе по исходному коду, при этом сама документация размазывается по коду в виде комментариев, записанных в специальном формате [16, 17]. Использования этих систем требуют многие соглашения о кодировании, использовались они и в фирме где я работал.

В приведенном фрагменте — «pure virtual member» заменяет описание функции, обычно на этом месте пишут что именно делает функция. Кроме того, часто пишут и короткое, и полное описание (они по-разному отображаются в документации). Тег «@see» позволяет связывать функции (связи отображаются в документации) — есть другие типы связей, а еще якоря, ссылки, секции, параграфы и т.п. Теги @param используются для описания аргументов функции.

Пример взят без изменения в официальной документации и ярко демонстрирует недостатки комментариев doxygen. Вообще, комментарии в этом случае нужны лишь потому, что у функции и аргументов выбраны плохие имена. С другой стороны, если имена были бы выбраны правильно, то комментарии попросту бы их дублировали. Дополнительные пометки — такие как теги, секции и т.п. — быстро устаревают. Программист может изменить тело функции (находящееся в другом файле), а неактуальными окажутся пометки в файле описания функции.

В реальных программах недостатки таких комментариев еще более очевидны, т.к. в них нет непонятного «pure virtual member», а каждая функция решает вполне определенную проблему. Код, приведенный ниже, взят из статьи про разработку игры. Дописанные комментарии ничего по существу добавить не могут, однако значительно увеличивают размер исходного кода — очевидно, что на их написание и поддержку расходуется немало времени.

Поддерживать соответствие кода и документации тяжело в любом случае — при изменении функции надо изменять документацию. Системы типа doxygen смешивают документацию с кодом, но никак не решают проблему.

С другой стороны, чтобы использовать doxygen, совсем не обязательно писать дополнительные комментарии. Если в вашей программе используются нормальные имена, то и документация получится съедобной — система doxygen построит вам нужные диаграммы (не только такую, как приведена ниже) и упакует все в удобный для чтения формат:

диаграмма классов doxygen

Выводы этой статьи состоят в том, что:

  1. форматировать код надо. Единообразно;
  2. правильные имена переменных могут сильно помочь при поддержке проекта;
  3. комментарии не решают проблемы плохого кода;
  4. современные инструменты разработки могут значительно облегчить поддержку и улучшить код;
  5. не всем советам «чистого кода» надо слепо следовать — часть из них может навредить.

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

Кстати, вопросы именования переменных и некоторые связанные с этим проблемы, относящиеся именно к языку С++, а также конструктивную критику Венгерской нотации можно прочитать в отдельной статье: «Именование переменных и констант в С++» [19].

Стиль оформления кода в .NET приложениях. Встречался ли вам ад в коде?

Работал в одной организации полтора года, написал сам несколько проектов. код в плане оформления просто чуть ли не идеален. Без всякой чуши типа венгерской нотации и т.д.

Поясняю. Если есть нормальная IDE, то венгерская нотация нафиг не нужна, код превращается в рябь из смеси сокращений, которые только раздражают. Навёл мышь, увидел тип данных, а так по сути всё и так понятно, когда на код смотришь. Нажал на переменную, подсветилась везде в коде она. Всё просто и ясно.

Я видел код, в котором переменные выглядит так:

А-а-а, он серьёзно? Нафига писать, что это Array (ar)? Почему после ar следующее слово с маленькой буквы? Код для кого пишется для людей или просто, чтобы он был как можно менее читабельным?

Зачем писать С в начале названия класса, если весь дотнет написан в нормальном, человеческом стиле? Ну это ещё ладно, это куда ни шло, хотя читать тяжко такое.

Название переменной ob — это вообще что за жесть? Почему не container? Дураку понятно, что это объект там будет на момент выполнения.

В общем, я когда читал подобный код на новой работе, я подумывал послать всё и уволиться оттуда, ибо там тонные такого кала. И неизвестно разрешат ли мне всё это рефакторить и приводить в нормальный вид.

Собственно вы поняли, что устроился я на новую работу. Зарплата больше в 2 раза, чем на прошлой работе, только это держит. Ну и я не всемогущ, тоже мне есть чему учиться, к примеру, T-SQL нужно учить, работу с БД и много другого. То есть я не гений, но такие мелочи реально напрягают.

Кстати, это далеко не самое худшее. Самое худшее это жуткий ппц в виде ужасного оформления классов в разных стилях. Всё перемешано, где-то методы сверху, конструктор посередине, поля вообще везде разбросаны. Где-то каждое поле свойства над свойством вплотную, этот ад вообще тяжело читать. Нафига хранить поле рядом? Ну напиши ещё в комментариях в какой папке лежит этот класс тогда до кучи. Над методами простые комментарии, а не XML или их вообще нет, но зато всё описано в документации с ужасными названиями документов, ориентироваться в них очень непросто, но можно. В разных классах разные отступы. Почти все классы в основном проекте лежат, никаких папок и соответствия им нэймспэйсов (за редким исключением). Названия файлов в проекте не соответствуют классам внутри них. Это реально ад! У меня нет слов.

А у вас было подобное? Вы как-то решали эту проблему?

Алёна C++

программирование для прагматиков

вторник, октября 06, 2009

Google C++ Style Gu >

Google C++ Style Guide как-то упомянули у меня в комментариях и я решила продублировать ссылку на него здесь. Это стандарт кодирования гугловых open source С++ проектов. Этот Style guide содержит некоторые спорные решения как то: отказ от исключений, отказ от RTTI.

42 коммент.:

А у нас на работе всё та же венгерская нотация. как я её недолюбливаю.

А я вот думаю, что Кодинг Стайл Гайд — это типа соглашение между программистами о том как нужно писать.

Только чем больше программистов учавствуют в этом соглашении — тем больше размер гайда.

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

У нас тоже пока никакого нету, хотя венгерскую нотацию мы не используем, слава богу.

2Андрей Валяев:
Мыслю, что было бы правильно в каждой команде иметь свой минимал гайд.

Дык так и есть. Почти везде где я работала были внутренние стандарты кодирования. У вас не так?

У нас есть негласные правила. Мы еще только учимся.. 🙂 Код ревьюв вот начали делать. Может скоро и документик какой сформулируем.

Корпоративного кодинг стайла у нас нету.. вернее когда-то было какое-то требование к оформлению исходников.. Ну там жесть. В начале каждого файла — шапка. перед каждой функцией — шапка. Никто его никогда не придерживался.

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

2Андрей Валяев:

Корпоративного кодинг стайла у нас нету.. вернее когда-то было какое-то требование к оформлению исходников.. Ну там жесть. В начале каждого файла — шапка. перед каждой функцией — шапка. Никто его никогда не придерживался.

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

Венгерскяа нотация — какой-то отстой. Она была хороша, когда нужно было смотреть на код и представлять тип переменной. Зачем это в эпоху IDE?

2Денис Радченко: Ну изначально префиксы обозначали вовсе не это.

Джоэл про это писал.

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

Типа того: xPos = yPos — сразу видно что ерунда. 🙂

Но потом кто-то придумал кодировать тип, и пошло — поехало.

2 Андрей Валяев:
«глобальную категорию переменной» — не совсем точно. Скорее «суть, назначение», чтобы нельзя было

currentCell = currentRow;
даже если обе переменные типа int.
А префиксы определяющие область видимости были в оригинальном документе.

2Денис Радченко:
А не все сейчас IDE и используют. Мне, например, простую идею проще быстро набросать в блокноте, а потом вставить в Студию, ибо перегружена оная кучей фич.
И такой вопрос: коде ревью Вы тоже из IDE делаете?

Вполне себе разумный coding standard. Особенно соглашусь с фразой «BE CONSISTENT».

Из спорных моментов отмечу неиспользование исключений, но и здесь мотивация ясна. К тому же: «Things would probably be different if we had to do it all over again from scratch.» С остальным примириться совсем легко.

А меня еще раздражают отступы пробелами. по моему, на порядок проще один раз нажать на таб, чем выравнивать код пробелами (хотя для IDE и продвинутых редакторов это и не актуально). У них какой-то микс K&R и GNU стайла.

Но еще хуже, когда выравнивается что-то в конце строк, например комментарии. Может быть выглядит красиво, но выравнивать это снова при каждой модификации — неоправданный гемор. 🙂

Лично я кодревьюв делаю в kdiff3, который вызывается непосредственно из перфорса. ревьювить постоянно все — бессмысленно, надо смотреть на то, что изменилось.

boost так же гадость уже лишь из-за изобилия исключений. какая прелесть от 3х строчной функции получить в лоб исключением? зачем RTTI, когда всё делается проще и быстрей?
странно что разработчика игр это волнует больше чем эффективность/масштабируемость

Спасибо за ссылку, добавлю в свой ToRead-список.
В свое время для меня было в какой-то мере откровением прочесть «Joint Strike Fighter Air Vehicle, C++ Coding Standards, December 2005». Стандарт кодирования на С++, принятый в Lockheed Martin Corporation при разработке многоцелевого ударного истребителя. Не менее серьезная контора и серьезный проект.
Так вот там тоже попадались странные на первый взгляд правила, вроде отказа от исключений и рекурсий.
Кстати, по поводу исключений Спольски, если я не ошибаюсь, написал в той же самой статье, в которой он защищал Венгерскую нотацию (в оригинальной ее трактовке).

Отказ от исключений предлагаю продолжить: предлагаю правило: отказ от множественных return в функции (гыгы).

Можно все запретить.

У меня все будут счастливы, а кто не будет — того я. (с) Бармалей

Только каждую возможность придумывали не просто так. у auto_ptr тоже есть свой смысл. На мой взгляд исключения сильно упрощают код. Конечно этот механизм тяжелый, и это надо понимать. И конечно необдуманным испрользованием чего угодно можно здорово испохабить код.. Дык это можно сделать и несмотря на все запреты. 🙂

Вот те же исключения взять. может быть это не слишком быстрое по скорости решение. Но скорость имеет значение далеко не всегда. Тут нельзя столь голословно подходить — мы не используем исключений и точка. 🙂 Все зависит от требований к конкретной разработке.

Хотя для студентов — иначе никак. 🙂 Это опытный программист понимает что к чему, а студент может написать любую ерунду.

ЗЫ: На испытательный срок — один кодинг гайд, 5 лет отработал — другой. Через 10 лет программирования тебя отводят в секретную комнату, где лежит совершенно секретный кодинг гайд, в котором написано что нет никаких гайдов. 😀

На то он и C++, чтобы был выбор и широкие возможности. За что я его и люблю. И именно из-за своих больших возможностей C++, как никакой другой язык, пожалуй, нуждается в подобного рода сборниках правил — они как база, от которой следует по умолчанию отталкиваться при проектировании или написании программ.
И, как и всегда, из всяких правил есть исключения (pun intended). Но чтобы их допускать, нужны веские причины и достаточные полномочия.

2Андрей Валяев:
А меня еще раздражают отступы пробелами. по моему, на порядок проще один раз нажать на таб, чем выравнивать код пробелами (хотя для IDE и продвинутых редакторов это и не актуально).
Насчет табов и пробелов, нажимать много раз пробел не нужно — многие IDE позволяют настроить замену таба определенным количеством пробелов
плюс этого подхода проявляется когда открываеш код в каком то нестандартном вьювере и в нем скажем увтановленно значение таба вдвое больше чем в твоей родной IDE весь код магическим образом оказывается где то глубоко за правым краем экрана, а если табы заменены пробелами, то такого эффекта нет, форматирование кода остается одинаковым в любом вьювере

Ну а насчет того, какая нотация лучше, так это тема для отдельно вынесенного холовара где нибудь на просторах rsdn

Андрей Валяев: да-да 🙂 а кто не shared ptr, тот в Stl огребает море overhead’ов. И потом вопросы задает не «как сделать, чтобы не копировать сложные объекты в список», а «что вы возьмете, vector или list»? 🙂 А кто не auto ptr и не handle wrapper- зачем им С++ вообще?

Написание ПО для истребителей с использованием исключений, RTTI. Вы лулзность этой фразы не понимаете?)

>> Но скорость имеет значение далеко не всегда.
if (!привет мир) throw упс!
да)

99,9% ПО разрабатывается не для истребителей!

Да и Google вроде не занимается такой ерундой, как истребители.

И чтобы вот так вот, из за истребителей, запрещать RTTI и исключения?

Не хочу разводить холивар, но:
1) как и написано у Страуструпа — исключения должны оставаться исключениями, т.е. «бросать» их надо в исключительных ситуациях (т.е. в тех ситуациях, которые не являются обычными, предусмотренными логикой программы ветвлениями)
2) без RTTI (сам лично не использую вообще) и исключений это уже не C++, так как даже new «бросает» исключение (и это правильно, что бы там не писали в Google и Mozilla)
3) насчет JSF Coding Standard — там все под embedded заточено и в этом плане все разумно написано, но есть пример того как «подружить» «return error code» и «exception» — см. как используется boost::system::error_code в boost::asio (этот пример хорош еще и тем, что там как раз не «return» используется для возврата «error code»)
4) боязнь использовать что-то, потому что не на всех платформах компиляторы позволяют «это» (правильно) собрать (и в быстрый код) вполне разумна, но способствует увеличению парка недо-С++ компиляторов и сроку их жизни
5) надо трезво понимать, что серьезный код (больших объемов) так или иначе не сделать кроссплатформенным «от и до» (спросите у разработчиков Java-игр для мобильных телефонов) — в той или иной мере все равно придется проводить портирование — вопрос только в его объеме
6) исходя из [5] — не понятно, почему Google так боится исключений — единственное что приходит в голову — они просто не желают тратить время на обсуждение того, где можно «кидать exception», а где нельзя
7) ну и как вывод — без исключений не обойтись (если, конечно, не вывернуть и не «переизобрести» C++) и в любом случае их будут поддерживать все платформы (Windows CE и все, что на ней есть уже поддерживает) — вопрос только в том, всегда ли мы вправе «бросать» исключение — тут просто еще раз проштудировать Бьярна — у него пожалуй, самый взвешенный подход ко всему, что есть в C++

P.S. а мне все таки нравится JSF Coding Standard, но naming conventions больше импонируют STL и Boost C++ Libraries, хотя в если в команде принято другое (хорошо если еще JSF-подобное, а не Camel) то профессионализм 🙂 трубет строго подчиняться.

2Marat:
6) исходя из [5] — не понятно, почему Google так боится исключений — единственное что приходит в голову — они просто не желают тратить время на обсуждение того, где можно «кидать exception», а где нельзя

За Google не скажу, но везде, где я работала, исключения были либо запрещены стандартами кодирования, либо не рекомендовались к использованию. Причины: исключения повышают сложность кода и ухудшают читаемость.
AFAIK, исключения не используются в российском геймдеве в принципе. Не знаю как там в забугорье дела обстоят.

В этом стандарте меня лчно напрягло то, что запрещается использовать директивы using. В сочетании с boost’овскими (да и просто std) библиотеками, где любят на каждый чих создавать namespace, код быстро замусорится уточнениями контекста.

2Алёна:
1) Я не «бью в грудь» — юзайте исключения, но пытаюсь донести, что надо обязательно учитывать возможность появления исключений (хотя бы потому, что пишем на языке, в который они буквальныо «зашиты») — Java-way в плане исключений безобразен
2) предпочитаю
а) не бросать исключение, если можно обойтись без него,
б) гарантии Абрахамса, точнее стараюсь придерживаться только гарантии «неутечки ресурсов»
в) стараюсь не обрабатывать исключения (т.к. это по большей части ошибка) — просто даю программе «упасть» — тут я полностью согласен со Страуструпом
3) с практической стороны вызывает интерес то, как например, лично Вы поступаете с «new» (вот только не надо переписывать мнение разработчиков Qt или Mozilla — уже много раз читал, поэтому хватит просто ссылки)
4) Если использовать STL (или просто C++ Standard Library), то опять же без исключений «не получится» — понимаю, что в gamedev-е на С++ почти никто не использует STL (и C++ Standard Library? для чего же тогда они нужны? 🙂
5) использовать RAII и везде «защищаться» от исключений действительно не просто (посмотреть хотя бы в исходники boost::asio) — но исключения не так уж и запутывают код — сравните со множеством if-else (ACE vs. boost::asio).
6) «исключения для исключений» — если можно, то я стараюсь использовать boost::system::error_code (как в boost::asio — передавая его через ссылку), но есть и места, где без них не обойтись — конструктор, operator [] и т.д. любой знает эти примеры
7) насколько я вижу (и где-то читал — Вы наверняка тоже) — не такая уж и малая часть кода является no-throw.
9) все порываюсь изучить Intel TBB — неужели и там нет исключений? (я имею ввиду «совсем нет») — а это точно используется в «забугорном геймдеве» — недавно что-то там анонсировали в UE3
9) . все таки холивар. так что простите. просто интересно мнение — все таки «вариться в собственном соку» еще никому не пошло на пользу.

P.S. Я далеко не профи в C++, хотя и хотел бы. Да и в production на C++ почти ничего не писал, так что очень ценю мнение опытных разработчиков и стараюсь не навязывать свое.

2Marat:
1) Я не «бью в грудь» — юзайте исключения

Да я в общем тоже без всякого подтекста говорю. Просто вот так дела обстоят.

3) с практической стороны вызывает интерес то, как например, лично Вы поступаете с «new»

У нас свой менеджер памяти, оператор new переопределен. При каких-либо проблемах с памятью выдаем assert, который есть только в дебаге и который вырезается в релизе.

9) все порываюсь изучить Intel TBB — неужели и там нет исключений? (я имею ввиду «совсем нет») — а это точно используется в «забугорном геймдеве» — недавно что-то там анонсировали в UE3

Про Intel TBB я совсем не в курсе.

9) . все таки холивар. так что простите.

Да не, по-моему всё довольно конструктивно.

2Алёна
С менеджером памяти — ожидаемо, т.е. многие так и делают (Mozilla). А чем тогда этот вариант отличается от «обычного new» — в release нет исключений? значит, все таки, возвращаемое значение всегда проверяется на NULL (пока все же правильнее говорить «0»)? Если нет, то, значит, просто принимается, что если при тестах не было «out of memory», то и у пользователя тоже (никогда) не будет? Согласен, с тем, что это допустимо. Но «new» не единственное место — см. operator= и т.д. Конечно, операторы перегружать — последнее дело, но иногда все-таки нужно (как раз читабельность кода повышается). Я еще раз повторюсь, что прежде чем «бросить exception» надо «100 (10000. 00) раз подумать» — аналогично и для try-catch. Вот в связи с этим, мне кажется, Google просто «боится» терять время на «священные войны». Хотя игнорирование RAII еще никому на пользу не пошло. Да и «хороший C++ программист» не должен злоупотреблять (именно злоупотреблять) всем тем, что есть в C++ (неужели Google «своих» такими не считает?). Кстати, как Вам «Herb Sutter, Andrei Alexandrescu — C++ Coding Standards»? Это конечно не Google (и уж тем более не JSF), но лично мне кажется хорошей отправной точкой для построения своего (т.е. для полного включения).

2Marat:
С менеджером памяти — ожидаемо, т.е. многие так и делают (Mozilla). А чем тогда этот вариант отличается от «обычного new» — в release нет исключений?

Ммм. Ну можно сказать и так, да. В release нет исключений. Это, конечно, не является основным смыслом существования менеджера памяти.

2Алёна
Раз уж отошел от темы, то продолжу.

Что касается менеджера памяти:
1) интересно Ваше мнение по поводу https://www.hoard.org/
2) -//-//- по поводу memory allocator в Intel TBB (task memory allocator)
3) -//-//- custom memory allocation в boost::asio — конечно там из-за этого сильно осложняется (именно осложняется — как-нибудь соберусь и напишу про ее «тупую» реализацию) раздельная компиляция, но в «effective net code» это уже должно отходить на второй план.

Если что-то из этого не знаете (важнее «не просто много знать», а уметь эффективно использовать то, что знаешь — не так ли?), то прошу как-нибудь выкроить время и посмотреть — все же многие читают этот блог (из моих знакомых) и всем интересно Ваше мнение.

P.S. Это последний «пост» — больше «сорить» не к чему.

>> Причины: исключения повышают сложность кода и ухудшают читаемость.
я не верю всяким байкам о трудно читаемости при использовании goto, throw (и что там у вас ещё). скорость решает всйо. вротмненоги если в cryengine expressive c++! ибо в gamedev главное растрата тиков. не так ли? :))

>> И чтобы вот так вот, из за истребителей, запрещать RTTI и исключения?
нет конечно 🙂 более того я скажу что использую исключения (при инициализации ядра конструктор кидает если продолжать невозможно). но повсеместно использовать это глупо. давайте ещё virtual’ить все :))

я не верю всяким байкам о трудно читаемости при использовании goto, throw (и что там у вас ещё).

Не надо верить, правильно. Я проверяла goto на своей шкуре. Не понравилось.

в gamedev главное растрата тиков. не так ли? :))

Нет. Очень быстрая и очень глюкавая игра никому не нужна.

Очень быстрая и очень глюкавая игра никому не нужна
.net? 🙂

з.ы. вот почему cryengine и unreal делаются годами
з.з.ы. всё молчу :))

Коллега подсказал, что инкапсуляция и сокрытие реализации должно действовать не только в классах, но и на уровне модулей и подсистем. В частности, если есть «публичное» исключение Exc, то все остальные должны давиться и приводиться к нему.

Три года ранее. Компания Quest. Сервисы. Во всех случаях кидается исключение class Exc < strText, hresultCode >или его наследники- как писать по-другому тесты- не знаю. Сейчас использую в своей практике. Любой try заканчивается catch (Exc).

Собственно, точно так же, как в java писали try .. catch (throwable). Потому что проблемы натива нам пофик и были нужны исключительно для лога. И обязательно везде finally. иначе ресурсы ни фига не освободятся.

Думаю, WinAPI, тот же CreateFile внутри себя может легко кидать Exceptions. Наружу он дает код ошибки. По этому коду ошибки exception кидает уже мой Wrapper.

Эту же систему можно сделать в игре- один компонент внутри себя кидает унифицированное исключение Exc, сам его ловит на выходе и переделывает в код ошибки. Wrapper, использующий этот компонент, преобразует код ошибки в унифицированное исключение Exc. ну и т.д. 🙂 Смысла в скорости при передаче кода ошибки я не вижу :-).

Порадовали китайцы. В огромной системе из сотни проектов был только один, в котором разрешили exception’ы. Я специально переписывался с этим инженером, чтобы узнать, почему у него было просветление- ну, что он там использовал- медитацию, цигун. Оказалось, что он их потом запретил. «Потому что код уменьшается на N килобайтов».

Китайцы очень жестко следовали Qt: НИ ОДНОГО исключения. Только в коде не было анализа НИ ОДНОГО кода возврата. Для них НУЖНО писать throw «Wrong filename RTFM» :-).

P.S.: Автоматические тесты рулят.

Как по мне, то самое верное и важное утверждение по поводу стандартов кодирования: «Не столь важно, какие именно у вас стандарты кодирования, важно, что они есть, и все им следуют». Google C++ Style Guide — более чем достойный кандидат для основы стандартов кодирования и для размышлений в принципе. Особенно понравилось то, что для большинства решений есть описание, за, против и вывод.

Чесно говоря, очень странно читать после стольких лет существования исключений в мейнстримовых языках программирования про использование и неиспользование исключений. Тем более, что в ряде языков (Ruby, Python, Java, C#) — исключения вообще являются единственной формой извещения об ошибках.

Уж не знаю, насколько сильно исключения в современных C++ных компиляторах сказываются на скорости работы. Но вот на надежность и отказоустойчивость программ исключения влияют гораздо лучше, чем коды возврата или глобальный errno.

2Алёна:
>AFAIK, исключения не используются
>в российском геймдеве в принципе.

Почему же, есть компании, где используются вовсю. 🙂

>При каких-либо проблемах с памятью
>выдаем assert, который есть только
>в дебаге и который вырезается в
>релизе.

То есть, у пользователя при нехватке памяти игра просто упадёт?

2dtjurev:
Почему же, есть компании, где используются вовсю. 🙂

То есть, у пользователя при нехватке памяти игра просто упадёт?

У нас консоль, а не PC. Протестировали на одной — получаем такое же поведение на всех. Нет такого, что у тестеров памяти хватало, а у пользователя вдруг не хватает.

Плюс у нас суровый defensive программинг. Значения проверяются, но перед обращением.

Считаю, что эта тема для флудинга. не более того. в школе учат буковки аккуратно писать и что? все пишут как нравится. и это хорошо.

Считаю, что эта тема для флудинга. не более того.

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

Где-то прочитал отличный вывод на тему всех таких попыток «оптимизировать» codestyle C++ (запрещая использование чего-то — как исключений в случае Google):

«Чтобы эффективно писать на C++, придется использовать ВСЕ возможности языка.»

Это значит, что проектируя язык, Страуструп постепенно обнаруживал проблемы и закрывал их, выдумывая новые возможности, (эксцепшены, темплейты) поэтому отсутствие чего-либо — это невозможность сделать тот или иной код прямым. Т.е. отстрелянная нога СРАЗУ.

> Китайцы очень жестко следовали Qt: НИ ОДНОГО исключения. Только в коде не было анализа НИ ОДНОГО кода возврата.

Если очень жестко следовать Qt, то получится чудовищный код, в котором на каждый чих (i.е. в начале каждой функции, даже если она вида A+=B; ) делается до десяти проверок: а если у нас не нулевой указатель на параметры; а выглядит ли размер данных таким, как нужно; а доступны ли нам некие глобальные объекты (типа общего менеджера объектов — или он по каким-то причинам умер), а знает ли этот менеджер (который может быть удаленным сетевым сервером!) про объект, у которого мы собираемся что-то спросить.

Т.о. код раздувается в среднем в пять раз.

Куда проще заключить исключения в ifdef debug и радоваться жизни. (это могли бы сделать китайцы для экономии нескольких килобайт).

Благодарю за интересную статью и комментировавших — за дискуссию. Только смените пожалуйста ссылку в посте — сейчас обсуждение на Хабре находится на https://habrahabr.ru/links/38329/
Причём прямой поиск результатов не даёт ( https://habrahabr.ru/search/?q=Google+C%2B%2B+Style+Guide ), пришлось походить «путями нормальных героев».

Благодарю за интересную статью и комментировавших — за дискуссию. Только смените пожалуйста ссылку в посте

Стиль написания кода на С

1. Заголовочные файлы

Каждый .cc файл должен иметь ассоциированный с ним .h файл. Исключения:

  • юнит-тесты
  • небольшие .cc файлы, содержащие только функцию main() Каждый заголовочный файл должен быть самодостаточным, т.е. включать в себя все другие, требуемые для нормальной работы, заголовки. Если в заголовочном файле объявлены шаблоны ( template ) или встроенные( inline ) функции, определите их в этом же файле. В заголовочном файле не должно быть:
  • определения обычных функций
  • определения данных
  • определения сложных константных объектов

Все заголовочные файлы должны иметь #define , для того чтобы избежать множественного включения. Формат имени должен иметь следующий формат: _ _ _H_ Чтобы гарантировать уникальность, имена должны быть основаны на полном пути в дереве исходных текстов проекта. Например, файл Foo / SRC / бар / baz.h в проекте Foo имеет следующее определение #define :

Конструкция #ifndef … #endif используется для предотвращения повторного включения заголовочного файла.

2. Правила наименования

  • Имена переменных, структур и функции пишутся маленькими буквами, слова разделяются символом подчеркивания “_”
  • При использовании директивы #define идентификатор следует писать большими буквами
  • Слова в именах файлов разделяются символом подчеркивания «_»: ( my_file.c )
  • Имя класса должно быть существительным
  • Имя переменной должно быть существительным и характеризовать выполняемую ей роль
  • Все буквы в именах константных переменных – заглавные

3. Отступы и размещение объявлений данных

Все отступы должны занимать ровно 4 пробела. А при расстановке фигурных скобок открывающаяся скобка не переносится на следующую строку:

  • объявление функции
  • объявление структуры/класса
  • перечисление
  • инициализация структуры/массива
  • операторы цикла, ветвления и пр. ( if, while, for, switch, case, do ) Операторы тела цикла, ветвления и пр. должны быть выделены в фигурные скобки независимо от их количества:

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

Если аргументы declarator-а переносятся на другую строку, то разделяющая запятая остается на строке как последний символ, перед тем как перенести все на другую строку. Аргументы с использованием таких операторов, как И, ИЛИ и пр. должны быть разделены на логически законченные части и помещены на отдельные строки каждой такой части:

Перед скобками после названия функции пробелов быть не должно. Также внутри скобок (после открывающейся скобки и перед закрывающейся скобкой) пробелов быть не должно. Но внутри скобок (при перечислении параметров функции) параметры должны быть разделены запятой и пробелом. После объявления функции без пробелов следует поставить точку с запятой: function(x, y, z);

3.2. Размещение объявлений данных

При объявлении указателей располагайте звездочку(*) рядом с типом переменной:

Объявляйте переменные рядом с местом их первого использования, если есть возможность то и определяйте значение переменной. Этот вариант предпочтительнее, чем объявление переменных в одном большом блоке:

Разумно упорядочивайте объявления, например по типам:

4.1. Унарные операторы

Унарные операторы записываются без пробелов между ними и их операндами: !p

4.2. Бинарные операторы

Следующие бинарные операторы записываются без пробела вокруг них:

  • -> (обращение к члену структуры по ссылке). Пример: me->foo
  • . (обращение к члену структуры напрямую). Пример: s.foo
  • [] (обращение к элементу массива). Пример: a[i]
  • () (вызов функции). Пример: foo(x, y, z) Бинарные арифметические операторы, операторы составного присваивания и операторы сравнения выделяются с двух сторон пробелами:
  • c1 == c2
  • x + y
  • i += 2

4.3. Условный оператор if

Оценка сложного условия лучше всего достигается через явные условные операторы. Конструкцию ?: можно использовать в следующих случаях:

  • инициализация
  • правая часть операнда присваивания (но без использования совместно с другими операторами)
  • возвращающее значение

Пример использования условного оператора с правильным форматированием:

4.4. Оператор switch

Пример использования оператора switch с правильным форматированием:

4.5. Операторы цикла

Пример использования оператора цикла for с правильным форматированием:

Пример использования оператора цикла while с правильным форматированием:

Пример использования оператора цикла do … while с правильным форматированием:

5.1 Начало файла

Начинайте каждый файл с комментария с описанием класса в следующем виде:

5.2. Не комментировать устаревший код

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

5.3. Оформление комментария

Для оформления комментариев и управляющих слов используется следующий формат:

  • /** …. */ — полное описание
  • // …. – краткое описание
  • для выделения управляющих ключевых слов, команд используется символ «@» ( @namespace , @param ) Если комментарий большой, то можно использовать команду @brief в блоке комментария:
  • Home
  • Andro > Show 31 more pages…
  1. Стили кодирования
  • [Java](Код стайл для языка Java)
  • [C/C++](Стиль написания кода на С )
  • [C#](Стиль написания кода на С# )
  • [Swift](Руководство по оформлению кода на языке Swift )
  • Написание комментариев к коммитам
  1. Andro >
    1. Форматы файлов
    • [.bmp](Cтруктура хранения bmp файлов)
    • [.jpg](Cтруктура хранения jpg файлов)
    • [.png](Cтруктура хранения png файлов)
    1. Алгоритмы шифрования
    • Кодирование информации псевдослучайными последовательностями чисел
    • Визуальная криптография
    • Схема разделения секретной визуальной информации
    • Шифрование RGB изображения с помощью Фурье образа
    • RSA-шифрование .bmp файлов
    1. Примеры использования
    • [Библиотека матричной алгебры](Пример использования библиотеки матричной алгебры)
    1. Описание процесса кодирования файла
    2. Способ обезопасить использование приложения
    3. Java фасад библиотеки алгоритмов
    4. Алгоритм шифрования bmp на java заглушке
    1. Матричная арифметика
    • [A+B](Сложение матриц)
    • [A*p](Умножение матрицы на скаляр)
    • [A*B](Умножение матриц)
    • [Обратные матрицы](Нахождение обратной матрицы)
    1. Взятие по модулю
    • [A mod p](Взятие матрицы по модулю простого числа)
    • [A mod P](Взятие матрицы по модулю — матрицы из простых чисел)
    1. Суперпозиция (модуль — простое число)
    • [A+B mod p](Сложение матриц по модулю простого числа)
    • [A*c mod p](Умножение матрицы на скаляр по модулю простого числа)
    • [A*B mod p](Умножение матриц по модулю простого числа)
    1. Суперпозиция (модуль — матрицы из простых чисел)
    • [A+B mod P](Сложение матриц по модулю — матрице простых чисел)
    • [A*c mod P](Умножение матрицы на скаляр по модулю — матрице простых чисел)
    • [A*B mod P](Умножение матриц по модулю — матрице простых чисел)
    1. [Утечки памяти](Memory Leaks)
    2. [Базовые цвета](Базовые цвета)
    3. [Clean Architecture](Clean Architecture)
    Clone this wiki locally
    • © 2020 GitHub , Inc.
    • Terms
    • Privacy
    • Security
    • Status
    • Help

    You can’t perform that action at this time.

    You signed in with another tab or window. Reload to refresh your session. You signed out in another tab or window. Reload to refresh your session.

    VS Code в связке с С++ (windows)

    Помогите запустить (то есть собрать (build) и отладить) код с++ в vsCode на windows 10. У меня уже установлен VS Community 2020 и расширение С/С++.
    Часто приходиться открывать однофайловые программы. Именно для этого хочу использовать VS Code. Возможность дебага не важна, но если есть возможность, то скажите.

    Что у меня уже получается. С помощью этой инструкции я могу собрать проект.
    Для этого:
    1. Установить плагин и перезагрузить программу
    2. Открываю VSCode.
    3. «Файл-Открыть папку» и выбираю папку где находится код
    4. В папке с вашим кодом создаем файл: build.bat , куда вставляем этот код:

    5. В папке открываю файл с кодом и нажимаю ctrl+shift+B
    6. 7. 8. 9. В открытой папке появляется папка «.vscode» а в ней «tasks.json» 10. В место этого вставляем это:

    11. Нажимаем опять ctrl+shift+B и видим что создался файл hello.exe и другие.

    Этот процесс можно как то автоматизировать? Еще в bat-файле можно как то передавать имя cpp-файла, что бы exe был с таким же именем? Что у меня не так с кодировкой может кто знает? И я не могу запустить отладку.

    1 ответ 1

    Если я все понял правильно, то хочется простой вещи — уметь открыть файл с с++ кодом (простенький хелло-ворд) и уметь скомпилить-запустить одной кнопкой (мне это также хотелось и vscode предоставляет такую возможность легко сделать в линуксе, но не в винде).

    Я нашел следующий способ.

    • Установить расширение CodeRunner
    • Теперь плугин нужно настроить. Открываем настройки ( Ctrl + , ) и ищем секцию «code-runner.executorMap», напротив ее нажимаем карандашик и справа в окно копируется кусок json с настройками. Там ищем для нашего расширения (cpp) и видим там для gcc. Меняем на такую строку «cpp»: «\»C:\\Program Files (x86)\\Microsoft Visual Studio\\2020\\Professional\\VC\\Auxiliary\\Build\\vcvars64.bat\» && cd $dir && cl $fileName /Fe$fileNameWithoutExt.exe && $dir$fileNameWithoutExt.exe»
    • готово

    В строке в самом начале запускается батник, который настраивает окрущение для компилятора. Возможно, Нужно будет его поискать самостоятельно и подменить путь/имя (а это точно нужно будет сделать, если винда 32битная к примеру)

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

    Отладку можно попробовать настроить, но я до этого не дошел (под линуксом все работает:) ).

    Новый курс программирования для iOS 9 на Swift от Стэнфордского университета доступен бесплатно через iTunes

    На этой неделе Стэнфордский университет запустил в iTunes U новый курс по разработке iOS-приложений. Курс программирования, включающий работу с iOS 9 и Swift, был разработан профессором университета Полом Хегарти (Paul Hegarty).

    Курс распространяется бесплатно через iTunes и предлагает всем желающим возможность научиться создавать приложения для iOS. Для того, чтобы прослушать курс, потребуется знание английского языка и iTunes.

    Регистрация на курс проходит в несколько секунд после нажатия кнопки «Подписаться». Приложение также предупредит пользователя о том, что курс может содержать платные материалы. После этого пользователю будут доступны видео-записи лекций.

    В курсе CS 193 P добавлена разработка приложений для iOS 9 и язык программирования Swift.

    «Инструменты и API позволят создавать приложения для платформ iPhone и iPad при помощи iOS SDK. Дизайн пользовательского интерфейса и взаимодействия использует технологии мультитач. Объектно-ориентированное проектирование использует парадигму «модель-представление-контроллер», управление памятью и язык программирования Swift. В числе других тем: анимация, управление питанием мобильного устройства, многопоточность, обсуждение производительности и др.», — говорится в описании курса.

    Соглашения по оформлению кода команды RSDN

    Автор: RSDN Team
    Источник: RSDN Magazine #1-2004

    Опубликовано: 27.02.2003
    Исправлено: 15.04.2009
    Версия текста: 1.0.1

    Введение

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

    Примеры внутри этого документа даются на языке C#, и вообще, все соглашения в первую очередь ориентированны на разработку, ведущуюся с использованием C#, но эти правила применимы и к другим языка (конечно, с учетом их специфики).

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

    Список терминов

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

    • operator – оператор (например, +, -, *, !)
    • statement – инструкция (например, «a = b;», «if (a) <>»)
    • expression – выражение (например, «a – b + c», «a == 1»)

    Именование идентификаторов


    Общие правила


    1. Помните! Код чаще читается, чем пишется, поэтому не экономьте на понятности и чистоте кода ради скорости набора.
    2. Не используйте малопонятные префиксы или суффиксы (например, венгерскую нотацию), современные языки и средства разработки позволяют контролировать типы данных на этапе разработки и сборки.
    3. Не используйте подчеркивание для отделения слов внутри идентификаторов, это удлиняет идентификаторы и затрудняет чтение. Вместо этого используйте стиль именования Кемел или Паскаль.
    4. Старайтесь не использовать сокращения лишний раз, помните о тех, кто читает код.
    5. Старайтесь делать имена идентификаторов как можно короче (но не в ущерб читабельности). Помните, что современные языки позволяют формировать имя из пространств имен и типов. Главное, чтобы смысл идентификатора был понятен в используемом контексте. Например, количество элементов коллекции лучше назвать Count, а не CountOfElementsInMyCollection.
    6. Когда придумываете название для нового, общедоступного (public) класса, пространства имен или интерфейса, старайтесь не использовать имена, потенциально или явно конфликтующие со стандартными идентификаторами.
    7. Предпочтительно использовать имена, которые ясно и четко описывают предназначение и/или смысл сущности.
    8. Старайтесь не использовать для разных сущностей имена, отличающиеся только регистром букв. Разрабатываемые вами компоненты могут быть использованы из языков, не различающих регистр, и некоторые методы (или даже весь компонент) окажутся недоступными.
    9. Старайтесь использовать имена с простым написанием. Их легче читать и набирать. Избегайте (в разумных пределах) использования слов с двойными буквами, сложным чередованием согласных. Прежде, чем остановиться в выборе имени, убедитесь, что оно легко пишется и однозначно воспринимается на слух. Если оно с трудом читается, и вы ошибаетесь при его наборе, возможно, стоит выбрать другое.

    Стили использования регистра букв


    • Паскаль – указание этого стиля оформления идентификатора обозначает, что первая буква заглавная и все последующие первые буквы слов тоже заглавные. Например, B ack C olor, L ast M odified, D ate T ime.
    • Кэмел – указание этого стиля обозначает, что первая буква строчная, а остальные первые буквы слов заглавные. Например, b order C olor, a ccess T ime, t emplate N ame.

    Сокращения


    1. Не используйте аббревиатуры или неполные слова в идентификаторах, если только они не являются общепринятыми. Например, пишите GetWindow, а не GetWin.
    2. Не используйте акронимы, если они не общеприняты в области информационных технологий.
    3. Широко распространенные акронимы используйте для замены длинных фраз. Например, UI вместо User Interface или Olap вместо On-line Analytical Processing.
    4. Если имеется идентификатор длиной менее трех букв, являющийся сокращением, то его записывают заглавными буквами, например System. IO, System.Web. UI. Имена длиннее двух букв записывайте в стиле Паскаль или Кэмел, например Guid, Xml, xmlDocument.

    Выбор слов


    1. Не используйте имена, совпадающие с глобальными пространствами имен, такими, как System и Microsoft. Старайтесь по возможности избегать совпадения с названиями других сущностей .NET Framework.
    2. Ниже приводится список имен, использование которых нежелательно:

    AddHandlerAddressOfAliasAndAnsi
    AsAssemblyAutoBaseBoolean
    ByRefByteByValCallCase
    CatchCBoolCByteCCharCDate
    CDecCDblCharCIntClass
    CLngCObjConstCShortCSng
    CStrCTypeDateDecimalDeclare
    DefaultDelegateDimDoDouble
    EachElseElseIfEndEnum
    EraseErrorEventExitExternalSource
    FalseFinalizeFinallyFloatFor
    FriendFunctionGetGetTypeGoto
    HandlesIfImplementsImportsIn
    InheritsIntegerInterfaceIsLet
    LibLikeLongLoopMe
    ModModuleMustInheritMustOverrideMyBase
    MyClassNamespaceNewNextNot
    NothingNotInheritableNotOverridableObjectOn
    OptionOptionalOrOverloadsOverridable
    OverridesParamArrayPreservePrivateProperty
    ProtectedPublicRaiseEventReadOnlyReDim
    RegionREMRemoveHandlerResumeReturn
    SelectSetShadowsSharedShort
    SingleStaticStepStopString
    StructureSubSyncLockThenThrow
    ToTrueTryTypeOfUnicode
    UntilvolatileWhenWhileWith
    WithEventsWriteOnlyXorevalextends
    instanceofpackagevar

    Пространства имен


    1. Для пространства имен используйте имя компании, затем название продукта и, возможно, название подсистемы или существенной части проекта. Например, Rsdn.Framework, Rsdn.MegaTool.Scanner.
    2. Используйте стиль Паскаль для регистра букв.
    3. При объявлении пространства имен используйте единственную директиву namespace с полным именем пространства имен. Не используйте вложенные объявления пространств имен. Это замечание не относится к С++/MС++, так как в них нет отличной от вложенных пространств имен возможности создавать составные пространства имен.
    4. Множественное число следует использовать в случае, если пространство имен объединяет некоторое количество разных, но семантически похожих сущностей. И наоборот, когда пространство имен содержит некую подсистему, стоит использовать единственное число. Сравните: Rsdn.Collections, но не Rsdn.Collection; Rsdn.Controls, но не Rsdn.Control; Rsdn.Network, но не Rsdn.Networks; Rsdn.Web, но не Rsdn.Webs;
    5. Не используйте одно и то же имя для класса и пространства имен. Например, не используйте класс Debug и пространство имен Debug .

    Импорт пространств имен (директива using)


    1. Перечислять импортируемые пространства имен необходимо в следующей последовательности: пространства имен .NET Framework, пространства имен сторонних производителей, собственные пространства имен из других проектов, пространства имен из текущего проекта. Каждый такой раздел должен отделяться одной пустой строкой, а имена внутри раздела должны быть отсортированы по алфавиту.
    2. Директивы using, содержащие alias, должны идти в конце соответствующих разделов, и также быть упорядоченными по алфавиту.

    1. Все не вложенные типы (размещаемые в пространствах имен или непосредственно в глобальном пространстве), за исключением делегатов, должны находиться в отдельных файлах.
    2. Старайтесь объявлять вложенные типы в начале внешнего типа.
    3. Старайтесь не делать излишней вложенности типов. Помните, что вложенными должны быть только тесно связанные типы.

    Элементы типов (type members)


    1. Элементы типов должны отделяться одной строкой друг от друга. Вложенные типы должны отделяться двумя строками. При объявлении большого количества полей, используемых внутри класса (не публичных), можно опускать пустую строку (особенно если поля отделены XML-комментариями).

    Классы/Структуры


    1. Используйте существительное (одно или несколько прилагательных и существительное) для имени класса.
    2. Используйте стиль Паскаль для регистра букв.
    3. Не используйте специальных префиксов, поясняющих, что это класс. Например, FileStream , а не CFileStream .
    4. В подходящих случаях используйте составные слова для производных классов, где вторая часть слова поясняет базовый класс. К примеру, ApplicationException – вполне подходящее название для класса, унаследованного от Exception , поскольку ApplicationException является наследником класса Exception . Не стоит, однако злоупотреблять этим методом, пользуйтесь им разумно. К примеру, Button – вполне подходящее название для класса, производного от Control. Общее правило может быть, например, таким: «Если производный класс незначительно меняет свойства, поведение или внешний вид базового, используйте составные слова. Если класс значительно расширяет или меняет поведение базового, используйте новое существительное, отражающее суть производного класса». LinkLabel незначительно меняет внешний вид и поведение Label и, соответственно, использует составное имя.
    5. Используйте составное имя, когда класс принадлежит некоторой специфичной категории, например FileStream, StringCollection, IntegrityException. Это относится к классам, которые являются потоками (Stream), коллекциями (Collection, Queue, Stack), ассоциативными контейнерами (Dictionary), исключениями (Exception).
    6. Для классов-наследников, реализующих интерфейс IDictionary рекомендуется использовать тройное имя в виде To Dictionary. Вместо Dictionary можно использовать слово Map. Если это очевидно, можно опускать название значения. Примеры: StringToStringDictionary, StringToIntegerMap или KeywordMap. Переменным такого типа рекомендуется давать более конкретное семантическое название, например userToPasswordMap (user password), nameServiceDictionary (name service).
    7. Для базового класса, предназначенного не для прямого использования, а для наследования, следует использовать суффикс Base. Например, CollectionBase. Такие классы также стоит делать абстрактными.
    8. Коллекциям (реализующим интерфейс ICollection/IList) нужно давать имя в виде Collection. Переменным же этих типов лучше давать имена, являющиеся множественным числом от элемента. Например, коллекция кнопок должна иметь имя ButtonCollection, а переменная buttons.

    Интерфейсы


    1. Используйте описывающее существительное, прилагательное или одно или несколько прилагательных и существительное для идентификатора интерфейса. Например, IComponent – это описывающее существительное, ICustomAttributeProvider – это конкретизированное прилагательными существительное, а IPersistable – это характеризующее прилагательное.
    2. Используйте стиль Паскаль для регистра букв.
    3. Используйте префикс I (заглавная i) для интерфейсов, чтобы уточнить, что тип является интерфейсом. Старайтесь избегать интерфейсов с двумя I в начале, например IIdentifiable. Попробуйте подобрать синоним, например IRecognizable.
    4. Для пары класс-интерфейс, в которой класс является некоторой стандартной или эталонной реализацией интерфейса, используйте одинаковые имена, отличающиеся только префиксом I для интерфейса. Например, IConfigurationManager и ConfigurationManager.

    Атрибуты


    1. Класс, являющийся атрибутом, должен иметь суффикс Attribute. Ни один класс, атрибутом не являющийся, не должен иметь такого суффикса. Если семантика класса требует в названии слова что-то вроде Attribute, используйте синонимы, например Descriptor, Sign, Qualifier, Specifier, Declarator.

    Перечисления


    1. Используйте стиль Паскаль для регистра букв в названии и значениях перечисления.
    2. Не используйте суффикс Enum в названии типа, вместо этого используйте более конкретный суффикс, например Style, Type, Mode, State. Чтобы код легче читался, используйте следующее правило: «Название перечисления + is + значение должно образовывать простое предложение». Например: BorderStyle.Single ( Border style is single, ThreadState.Aborted Thread state is “aborted”.
    3. Если перечисление обладает атрибутом [Flags], используйте множественное число или суффикс Flags.
    4. Записывайте значения перечисления на отдельных строках. Если элементы имеют определенный семантический порядок, описывайте их именно так, иначе используйте алфавитный порядок.
    5. Если значение одного из членов перечисления зависит от других, используйте булевы операции (&, |, ^), а не литеральные константы.
    6. Имена членов перечисления не должны содержать имени перечисления и другой не относящейся к конкретному значению информации.

    1. Непубличные поля (private, protected и protected internal) именуются в стиле Кэмел и начинаются с префикса _.
    2. Публичные поля именуются в соответствии с правилами именования свойств.
    3. Одна декларация должна содержать не более одного поля и должна располагаться на одной строке.

    1. Публичные поля должны в обязательном порядке документироваться XML-комментариями. Желательно снабжать XML-комментариями и непубличные поля.
    2. Обращаясь к публичным полям старайтесь избегать их передачи по ссылке, т.к. велика вероятность того, что в следующих версиях приложения эти поля могут стать свойствами.

    Методы


    1. Используйте глаголы или комбинацию глагола и существительных и прилагательных для имен методов.
    2. Используйте стиль Паскаль для регистра букв (вне зависимости от области видимости метода).

    Свойства


    1. Используйте существительное или одно или несколько прилагательных и существительное для имени свойства.
    2. Используйте стиль Паскаль для регистра букв.
    3. В подходящих случаях используйте имя свойства, совпадающее с типом его значения. Одним из критериев для применения этого правила является наличие единственного свойства со значением некоторого (нетривиального) типа.
    4. Старайтесь избегать использования имен свойств, совпадающих с названиями каких-либо типов, если значения этих свойств не являются значениями этих типов. В этом случае будет трудно получить доступ к статическим членам типа или значениям перечисления. Например, при использовании конструкции public int Color < get; set; >, обращение Color.Xxx будет рассматриваться как получение свойства Color и затем доступ к свойствам или методам этого значения, которое в данном случае будет являться типа System.Int32.
    5. Рассмотрите возможность включения имени типа в идентификатор свойства, особенно если этот тип – перечисление. Например, OuterBorderStyle , BackColor, SocketFlags.

    События


    1. Используйте суффикс EventHandler для делегатов, являющихся типами событий. Другие классы не должны использовать этот суффикс.
    2. Создавая событие в компонентах и control-ах, старайтесь описывать их по следующей схеме. Определите два параметра с именами sender и e. Параметр sender описывает объект, инициировавший событие, и всегда должен быть типа object, даже если возможно использование более конкретного типа. Второй параметр, e, должен содержать состояние и дополнительную информацию, соответствующую событию. Этот параметр должен быть конкретного типа, относящегося к событию.
    3. Делайте тип, описывающий связанную с событием информацию, производным от EventArgs, и используйте суффикс EventArgs . Другие классы, не описывающие информацию о событии, не должны использовать этот суффикс.
    4. Для имен событий старайтесь использовать глаголы, которые описывают производимое над объектом действие (например, Click, GotFocus или FontChanged).
    5. Не используйте суффиксы наподобие On, Before, After для идентификатора события. Используйте соответствующую форму глагола, например Closing перед закрытием и Closed после закрытия.
    6. При описании события также предоставляйте виртуальный protected-метод, который можно переопределить в классе-наследнике. Называйте такой метод OnXxx, где Xxx – имя события. В качестве параметров таких методов не следует передавать sender , так как – это всегда текущий объект (this).
    7. Пытайтесь подобрать стандартный делегат и название для своих событий. Например, если ваш элемент управления должен реагировать на нажатие кнопки мыши, следует использовать стандартное событие Click. Для элементов управления, обычно, такие события уже объявлены в базовом классе Control.

    Параметры


    1. Из имени и типа параметра должны быть понятны его назначение и смысл.
    2. Используйте стиль Кэмел для регистра букв в имени параметра.
    3. Старайтесь избегать указания типа в имени параметра.
    4. Не усложняйте прототип метода «зарезервированными» параметрами, которые, возможно, будут использоваться в будущих версиях реализации. Если в будущем понадобится новый параметр, используйте перегрузку методов.
    5. Имена параметров не должны совпадать с именами членов класса. Если этого все же не удается избежать, используйте ключевое слово this для разрешения конфликтов (допустимо различие в регистре или префиксе _ для полей классов ).

    Стиль кода


    Оформление


    1. Используйте табуляцию , а не пробелы для отступов. В средах типа VS лучше использовать режим табуляции. Его можно настроить в диалоге Options -> Text Editor -> Ваш_любимый_язык ->Tabs: Indenting = Smart, Tabs = Keep Tabs. В общем, это настройки по умолчанию для многих языков.
    2. При форматировании текста (кроме отступа в начале строки) используйте пробелы. Для этого удобно использовать режим Virtual Space, который в VS 2002 настраивается в Options -> Text Editor -> Ваш_любимый_язык -> General.
    3. Избегайте строк длиннее 78 символов, переносите инструкцию на другую строку при необходимости.
    4. При переносе части кода инструкций и описаний на другую строку вторая и последующая строки должны быть отбиты вправо на один отступ (табуляцию).
    5. Оставляйте запятую на предыдущей строке так же, как вы это делаете в обычных языках (русском, например).
    6. Избегайте лишних скобок, обрамляющих выражения целиком. Лишние скобки усложняют восприятие кода и увеличивают возможность ошибки. Если вы не уверены в приоритете операторов, лучше загляните в соответствующий раздел документации.
    7. Не размещайте несколько инструкций на одной строке. Каждая инструкция должна начинаться с новой строки.

    Пустые строки


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

    Пробелы в строке


    1. После запятой должен быть пробел. После точки с запятой, если она не последняя в строке (напр. в инструкции for), должен быть пробел. Перед запятой или точкой с запятой пробелы не ставятся.
    2. Все операторы должны быть отделены пробелом от операндов с обеих сторон.
    3. Логически связный блок регулярной структуры желательно форматировать в виде таблицы. При этом для выравнивания в таблице следует использовать пробелы, но не табуляцию. Среды типа VS автоматизируют процесс форматирования, вставляя пробелы или табуляции в соотвтествии с пользовательскими настройками. Будьте внимательны и проверяйте конечный результат, включая неотображаемые символы (для VS 2002 и старше – меню Edit->Advanced->View White Space).

    ПРИМЕЧАНИЕ

    Для упрощения работы можно использовать следующий трюк. Таблицу можно сформировать с помощью табуляции, выделить область прямоугольным выделением (Alt + курсор мыши вправо), а затем применить к этой области Edit->Advanced->Untabify Selection.

    Мастер Йода рекомендует:  8 заданий по C#, которые могут попасться на собеседовании
    Добавить комментарий