Соглашения о кодировании
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 |