Codestyle

Материал из Oxygen Engine
Перейти к: навигация, поиск

XRay Oxygen Codestyle

Введение

С++, это самый сложный, не эзотерический, язык. Самый гибкий, обладающий наибольшим количеством фич, при этом позволяя достигнуть необходимой производительности во всех ситуациях - он стал промышленым стандартом для самых сложных программных технологий и комплексов по всему миру. Но при всем этом - он самый опасный язык. В С++ легко написать код который работает _почти _всегда, код который было удобно писать, но невозможно читать. Так уж получилось, что дизайн языка не предполагает построение дисциплины хорошего кода для программиста (как Go, Haskell или Python), напротив, он полностью развязывает руки позволяя использовать любые подходы программирования. Столь широкие возможности следует лимитировать в рамках проекта, т.к. без этого проект превращается в плохо читаемую кашу из нескольких стилей, с разными подходами и методами.

Основа

Главная идея которая лежит в основе этого кодстайла - максимальная читабельность. Предполагается, что завтра тот код, что мы сейчас пишем - забудем, и нужно написать так, чтобы мы все вспомнили за наименьшее возможное время. Скорость написания кода - не приоритет. Если потребуется - следует потратить в два раза больше времени, если это улучшает читабельность и дальнейшую поддержку кода. Кодстайл автора (Giperion) не доконца применяется в проекте Oxygen, в силу старости самого проекта (учитываются ещё года X-Ray у GSC). Перевести все на новый кодстайл - дело крайне трудозатратное.

Описание

Мы любим Latest

  • atoi у нас не используется, используем atoi_17

Файлы

Файлы должны начинаться с след. расширений:

  • C: sultan.c
  • С++: sultan.cpp
  • CUDA C: sultan.cu
  • С/С++ header: sultan.h

Расширения .hpp и .cc не используются.

Заголовки

Инклуд страж вида: #pragma once Forward Declaration разрешает использовать умеренно. Точнее говоря: не более двух объявлений в заголовке. В целом все необходимые заголовки нужно подключать явно, при требований.

Переменные

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

DWORD LongNameWithSeveralWords;
const char* SomeString;

Однако есть несколько определённых случаев:

  • Индексы итераторов называются i или же Iter, т.к. это общеизвестно и не вредит читабельности. Пример
for (int i = 0; i < 1000; ++i)
  • Указатели на объекты можно предварять префиксом p (кроме строк). Например:
int* pSomeCounter;
  • Булeвые переменные идут с префиксом b:
bool bSomeCondition;
BOOL bAnotherCondition; // Тип BOOL использовать только по требованиям DirectX или WinAPI
  • Перечисления типа enum идут с префиксом e:
enum 
{
 eBegin = 0,
 eEnd
}

Венгерская нотация - не используется. Вставлять какие либо символы в начале или в конце (вроде '_') - не следует. Так же символьные типы `pcstr`, `LPCSTR` не приветствуются. Для числовых типов имеется ряд сокращений:

u - unsigned
s - signed

Например: 
u32 = unsigned int 
s64 = signed long long

Типы переменных

Тип переменных по возможности всегда указывается. Есть всего две ситуации, когда ставится auto: 1) Если переменная - лямбда. Лямбды сильно меняют свой тип даже при небольших изменениях, поэтому писать его не нужно. Но в этом случае название переменной должно оканчиваться на lambda. 2) Если переменная имеет слишком длинный тип (использующий несколько шаблонов). К такому, например, можно отнести итераторы std::vector/list/map.

Использовать auto, потому что "тип же очевиден" - запрещено.

Название функции

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

void FunctionExample();
void* GetPtr();

Приемлемые сокращения:

  • Ptr - pointer
  • IC - inline

Глобальные переменные

Глобальные переменные имеют префикс 'g_'.

Использование скобок в функциях или операторах

Скобка ставится на новой строке, а не на строке объявления, кроме случаев, когда используются return, break или continue.

if (SomeCondition)
{
   InvokeSomeFunction();
}

if (AnotherCondition) return;

switch (enumeration)
{
   case eEnumerationTypeOne:
        if (ThirdCondition) break;
        DoSomething();
   break;
}

Немного о циклах

  • Рекомендуем использовать for-each (Range-Base-For) из C++11
  • Численный итератор должен быть Unsigned типа, если же он не начинает/заканчивает отсчёт с отрицательного значения.