Соглашения о кодировании
1. Основные принципы
1. Целями внедрения настоящих соглашений являются стандартизация исходного кода проекта и приведение его к единому виду, что позволяет:
(i) снизить количество ошибок в программном коде и повысить его качество;
(ii) повысить эффективность работы команды разработчиков, снизить время онбординга новых разработчиков в команду;
(iii) формализовать критерии для выявления ошибок и улучшить автоматизированные механизмы, применяемые для контроля качества кода;
(iv) упростить восприятие кода и снизить нагрузку на память и зрение при чтении кода.
2. Настоящие соглашения обязательны к применению в коде Sky/IX.
3. В случае, если существующий код не соответствует настоящим соглашениям, он приводится в соответствие с ними при модификации.
4. Пункты соглашений, касающиеся оформления кода, применяются автоматически с использованием средств автоматического форматирования исходного кода при публикации кода в репозиторий проекта.
5. Пункты соглашений, касающиеся структуры и семантики исходного кода, проверяются вручную на ревью.
6. Настоящие правила не являются окончательными и могут дорабатываться по мере необходимости.
7. Дополнение настоящих соглашений производится итеративно, по мере выявления проблемных мест и возможностей для улучшения. Такая практика позволяет лучше оценить те или иные изменения, нежели одновременное внедрение большого числа изменений.
2. Общие положения
2.1. Разработка производится на языке C++. Используемый стандарт языка — C++23 (ISO/IEC 14882:2024).
2.2. В случаях, когда применение языка C++ невозможно, допускается использование языка C. Используемый стандарт языка — C23 (ISO/IEC 9899:2023).
2.3. Использование расширений GNU не допускается. Используемые расширения должны поддерживаться как минимум компиляторами CLang, GCC и Intel.
2.4. В качестве основного компилятора используется CLang версии 19 или более новый.
2.5. Для документирования исходного кода используется Doxygen.
3. Правила оформления
3.1. Кодировка файлов с исходным кодом — UTF-8.
3.2. Используются окончания строк UNIX (LF).
3.3. Размер отступа устанавливается равным 4 символам. Для создания отступов используются пробельные символы вместо табуляции.
3.4. Максимальная длина строки — 120 символов, рекомендуемая в общем случае — не более 80 символов.
3.5. В редких случаях, когда попытки сократить строку, превышающую 120 символов, приводят к ухудшению читаемости, допускается превышение лимита. На таких участках кода следует отключать автоматическое форматирование кода.
3.6. Комментарии пишутся на английском языке.
3.7. Использование специальных символов Unicode и эмодзи в исходном коде и комментариях запрещено.
3.8. Для комментариев (за исключением блоков Doxygen) используется
современный синтаксис (//). Начало комментария должно быть отделено одним
пробелом от открывающей последовательности:
// This is a well-formed comment
3.9. Допускается выравнивание объявлений переменных и присваиваний:
int a = 1;
long xyz = 2;
3.10. Аргументы унарных арифметических операций не отделяются пробелом от оператора:
*ptr++ = --i;
3.11. Аргументы бинарных арифметических и логических операций отделяются от оператора символом пробела, при этом между скобками и выражением пробелы не ставятся:
int a = 2 * (b + c) / d[4];
4. Правила именования
4.1. Имена функций, переменных и типов состоят из строчных букв, разделяемых
знаком подчеркивания: item, item_name и т.п.
4.2. Имена полей класса должны иметь префикс m_.
4.3. Имена интегральных типов должны иметь суффикс _t.
4.4. Для переменных, хранящих порядковый номер, следует использовать суффикс
idx (disk_idx).
4.5. Следует избегать избыточных сокращений, кроме стандартных (см. "Стандартные сокращения").
4.6. Имена булевых переменных должны подразумевать значения true или
false и позволять однозначно интерпретировать каждое из значений.
4.7. Имена булевых переменных должны быть утвердительными. Отрицание в имени переменной может привести к двойным отрицаниям в условиях. Для решения этой проблемы следует использовать пары антонимов (см. "Стандартные антономические пары").
5. Правила типизации
5.1. Для нулевого указателя используется ключевое слово nullptr.
Использование макроса NULL не допускается.
5.2. Для булевых переменных должен использоваться стандартный тип bool. Не
допускается использовать тип int для булевых значений.
5.3. Если переменная может принимать только положительные значения, должны использоваться беззнаковые типы. Это позволяет устранять многие типовые ошибки на этапе компиляции и статического анализа.
5.4. Для размеров и смещений объектов, структур, файлов и т.п. должны
использоваться стандартные типы size_t, ssize_t и off_t, определённые в
заголовочном файле <stddef.h>.
5.5. В форматных функциях printf(), scanf() и т.д. для типов size_t и
ssize_t следует использовать специальные спецификаторы %zu (%zx) и %zd
(%zi) соответственно.
5.6. Для целых чисел со строго заданным размером в битах, либо используемых
при взаимодействии с аппаратным обеспечением, должны использоваться стандартные
целочисленные типы, определённые в заголовочном файле <stdint.h>, такие как
int32_t, uint32_t, int_least32_t и т.п.
5.7. Если ситуация предусматривает семантический тип данных, должны
использоваться семантические типы данных. Например, при парсинге данных,
состоящих из октетов, в коде на C++ должен быть использован тип std::byte,
а в коде на C - определён типа octet_t, эквивалентный uint8_t:
typedef uint8_t octet_t;
5.8. Если функция не имеет аргументов, список аргументов должен быть объявлен
как void:
void some_func(void);
5.9. Если изменение данных не предусматривается, переменная, аргумент функции
или её возвращаемое значение должны быть объявлены с модификатором const.
6. Структура и декомпозиция
6.1. Объявление нескольких переменных на одной строке запрещено.
6.2. Обратные сравнения с константой запрещены.
6.3. Переиспользование одной и той же переменной для двух разных целей нежелательно. Исключения:
-
итераторы (
item,iter,node, …) и переменные циклов (i,j,k, …), объявление которых необходимо вне цикла (например, если необходимо иметь доступ к индексу, на котором цикл остановился); -
общие переменные кода ошибки/возврата (
err,rv).
7. Стандартные сокращения
| arg |
argument |
| avg |
average |
| buf |
buffer |
| cmd |
command |
| ctx |
context |
| config |
configuration |
| cb |
callback |
| crit |
critical |
| ctor |
constructor |
| dbg |
debug |
| dev |
device |
| dtor |
destructor |
| err |
error |
| env |
environment |
| fd |
file descriptor |
| fmt |
format |
| func |
function |
| id |
identifier |
| idx |
index |
| iter |
iterator |
| impl |
implementation |
| len |
length |
| lhs |
left-hand side |
| mem |
memory |
| msg |
message |
| num |
number |
| obj |
object |
| off |
offset |
| out |
output |
| param |
parameter |
| phys |
physical |
| ptr |
pointer |
| prop |
property |
| rv |
return value |
| req |
request |
| resp |
response |
| rhs |
right-hand side |
| sm |
state machine |
| spec |
specification |
| str |
string |
| sys |
system |
| thr |
thread |
| ver |
version |
| vol |
volume |
| warn |
warning |