Стандарт оформления кода — различия между версиями

Материал из SkyXEngine wiki
Перейти к: навигация, поиск
(Имена в коде)
Строка 12: Строка 12:
  
 
== Имена в коде ==
 
== Имена в коде ==
Имена переменных формируются в соответствии с венгерской нотацией, то есть сначала префикс/префиксы (как в таблицых) за префиксом/префиксами следует имя переменной в смешанном регистре, начиная с верхнего. Выделено 2 типа префиксов:
+
Имена переменных формируются в соответствии с венгерской нотацией, то есть сначала префикс/префиксы (как в таблицых) за префиксом/префиксами следует имя переменной в смешанном регистре, начиная с верхнего.  
 +
 
 +
===Префиксы===
 +
Выделено 2 типа префиксов:
 
* контекстный - определяет контекст переменной, например глобальное пространство имен, член класса, константа, интерфейс и прочее
 
* контекстный - определяет контекст переменной, например глобальное пространство имен, член класса, константа, интерфейс и прочее
 
* типовый - определяет тип переменной, строка, знаковое целочисленное и прочее
 
* типовый - определяет тип переменной, строка, знаковое целочисленное и прочее
Строка 96: Строка 99:
 
|}
 
|}
  
'''Префикс fn''' используется для переменной указателя который ссылается на функцию.
 
  
 
В именах переменных типа bool недопустимо использование отрицания.
 
В именах переменных типа bool недопустимо использование отрицания.
  
'''Имена типов/классов/структур''', должны быть обязательно написаны в смешанном регистре, начиная с верхнего: CPoint, CCamera
+
===Классы и структуры===
 +
 
 +
'''Имена классов/структур''', должны быть обязательно написаны в смешанном регистре, начиная с верхнего, при этом структуры должны быть без префикса присущего классу.
 +
 
 +
Пример имен классов:  
 +
* CPoint
 +
* CCamera
 +
 
 +
Пример имен структур:
 +
* VertexElement
 +
* AdapterDesc
  
Настоятельно рекомендуется не использовать префиксы имени проекта в именах типов/классов/структур, для их безотносительной идентификации.
+
Настоятельно рекомендуется не использовать префиксы имени проекта в именах типов/классов/структур, для их безотносительной идентификации во внутренней реализации программы/библиотеки. Во внешних файлах (подключаемых) допускается использование префикса проекта в именах.
  
 
'''Имена методов''' классов должны начинаться с нижнего регистра: getSpeedWalk
 
'''Имена методов''' классов должны начинаться с нижнего регистра: getSpeedWalk
Строка 109: Строка 121:
  
 
'''get/set''' должны быть использованы везде, где осуществляется прямой доступ к атрибуту. В данном случае get/set располагаются как можно ближе к началу имени, а возможно и в самом начале. Однако, все зависит от ситуации.
 
'''get/set''' должны быть использованы везде, где осуществляется прямой доступ к атрибуту. В данном случае get/set располагаются как можно ближе к началу имени, а возможно и в самом начале. Однако, все зависит от ситуации.
 
'''Имена типов в шаблонах''' должны формироваться следующим образом: первое основное можно называть T, остальные осмысленные имена большими буквами с подчеркиванием
 
 
'''Аббревиатуры в именах''' должны быть написаны в верхнем регистре, до и после должны быть буквы в нижнем регистре для явного выделения аббревиатуры: exportHTMLsource()
 
 
Для идентификации предназначения аргументов рекомендуется использовать пустые дефайны:
 
*_out – выходной, будет произведена запись
 
*_in – входящий, без записи
 
*_opt - опциональный, значение может быть недействительным (к примеру вместо указателей можно отправить 0)
 
 
Для представления массивов (наборов/коллекций) следует использовать множественное число объектов:
 
<syntaxhighlight lang="C++">vector<Point>  aPoints;</syntaxhighlight>
 
 
Переменным-итераторам следует давать имена i, j, k, для каждого цикла можно создавать дополнительную переменную il jl kl сохраняя длину массива, чтобы не вычислять каждый раз.
 
 
'''Имена пространств имён''' следует записывать в нижнем регистре.
 
<syntaxhighlight lang="C++">
 
namespace gdata
 
{};
 
</syntaxhighlight>
 
 
  
 
Настоятельно рекомендуется использование симметричных имен:
 
Настоятельно рекомендуется использование симметричных имен:
Строка 148: Строка 139:
 
*show/hide,  
 
*show/hide,  
 
*suspend/resume
 
*suspend/resume
 +
 +
===Шаблоны===
 +
'''Имена типов в шаблонах''' должны формироваться следующим образом: первое основное можно называть T, остальные осмысленные имена большими буквами с подчеркиванием
 +
 +
===Аббревиатуры===
 +
'''Аббревиатуры в именах''' должны быть написаны в верхнем регистре, до и после должны быть буквы в нижнем регистре для явного выделения аббревиатуры: exportHTMLsource()
 +
 +
===Массивы и коллекции===
 +
Для представления массивов (наборов/коллекций) следует использовать множественное число объектов:
 +
<syntaxhighlight lang="C++">vector<Point>  aPoints;</syntaxhighlight>
 +
 +
===Итераторы===
 +
Переменным-итераторам следует давать имена i, j, k, для каждого цикла можно создавать дополнительную переменную il jl kl сохраняя длину массива, чтобы не вычислять каждый раз.
 +
 +
===Пространства имен===
 +
'''Имена пространств имён''' следует записывать в нижнем регистре.
 +
<syntaxhighlight lang="C++">
 +
namespace gdata
 +
{};
 +
</syntaxhighlight>
 +
 +
===Метки аргументов===
 +
Для идентификации предназначения аргументов рекомендуется использовать пустые дефайны:
 +
*_out – выходной, будет произведена запись
 +
*_in – входящий, без записи
 +
*_opt - опциональный, значение может быть недействительным (к примеру вместо указателей можно отправить 0)
 +
  
 
===define и enum===
 
===define и enum===

Версия 08:45, 20 июня 2019

Стандарт оформления кода (code style) — это набор определенных правил при написании исходного кода, на определенном языке программирования.

Данный стандарт распространяется на:

  • исходный код движка,
  • шейдеры.


Общее правило именования

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

К примеру, класс CManagerTimes использует большое количество счетчиков времени (но кроме временных данных есть и другие). В этом случае логично предположить что «время» является ключевым фактором в именовании, значит, слово time будет наиболее приоритетным словом, и претендует на начало в имени, также многие параметры связаны со «скоростью» течения времени, но «скорость» описывает течение времени, значит «скорость» будет вторым по значимости словом, в итоге имя переменной будет: m_iTimeSpeed

Имена в коде

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

Префиксы

Выделено 2 типа префиксов:

  • контекстный - определяет контекст переменной, например глобальное пространство имен, член класса, константа, интерфейс и прочее
  • типовый - определяет тип переменной, строка, знаковое целочисленное и прочее
Таблица контекстных префиксов
Префикс Значения
g_ префикс для глобальной переменной
m_ префикс для переменной класса
c_ константа (префикс для типа)
I интерфейс
C класс

Константы только для локального применения, глобальные константы должны быть в define или enum.

Таблица типовых префиксов
Префикс Значения Тип
s строка объекты типа string
sz строка, ограниченная нулевым символом char []
ch символ char
i целочисленное значение int
u unsigned int
i8, i16, i32 int8_t, int16_t, int32_t
u8, u16, u32 uint8_t, uint16_t, uint32_t
b, is, can, has, should, use is – является ли, can – может ли, has – имеет ли, should – должен ли, use – используется ли bool
a массив array
v вектор float2, float3, float4 и прочее
id идентификатор int32_t
size размер size_t
p указатель *
o объект, экземпляр класса (не указатель)
t время
dt дата (и время)
fn переменная-функция


В именах переменных типа bool недопустимо использование отрицания.

Классы и структуры

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

Пример имен классов:

  • CPoint
  • CCamera

Пример имен структур:

  • VertexElement
  • AdapterDesc

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

Имена методов классов должны начинаться с нижнего регистра: getSpeedWalk

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

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

Настоятельно рекомендуется использование симметричных имен:

  • get/set,
  • add/remove,
  • create/destroy,
  • start/stop,
  • insert/delete,
  • increment/decrement,
  • old/new,
  • begin/end,
  • first/last,
  • up/down,
  • min/max,
  • next/previous,
  • old/new,
  • open/close,
  • show/hide,
  • suspend/resume

Шаблоны

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

Аббревиатуры

Аббревиатуры в именах должны быть написаны в верхнем регистре, до и после должны быть буквы в нижнем регистре для явного выделения аббревиатуры: exportHTMLsource()

Массивы и коллекции

Для представления массивов (наборов/коллекций) следует использовать множественное число объектов:

vector<Point>  aPoints;

Итераторы

Переменным-итераторам следует давать имена i, j, k, для каждого цикла можно создавать дополнительную переменную il jl kl сохраняя длину массива, чтобы не вычислять каждый раз.

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

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

namespace gdata 
{};

Метки аргументов

Для идентификации предназначения аргументов рекомендуется использовать пустые дефайны:

  • _out – выходной, будет произведена запись
  • _in – входящий, без записи
  • _opt - опциональный, значение может быть недействительным (к примеру вместо указателей можно отправить 0)


define и enum

define и enum создают константы, поэтому должны быть написаны только в верхнем регистре с использованием нижнего пробела: OBJ_MAX_LEN. При этом имена enum пишутся слитно с префиксом (например: GXTEXTURE_ADDRESS_MODE), а имена define с разделением (например: GX_MAX_SAMPLERS).

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

enum COLOR {
  COLOR_RED,
  COLOR_GREEN,
  COLOR_BLUE
};

Если определение дефайна должно вставляться в выражения, то оно должно оборачиваться в скобки:

#define A_ADD_B(a, b) (a + b)

иначе если определение дефайна является конечной инструкцией, оно должно быть обернуто в фигурные скобки:

#define PRINT(str) {printf(str);}

enum порождает префикс (опционально без префикса/постфикса названия enum'а), префикс можно сокращать до удобно читаемого/пишушегося названия. Примеры:

NPC_STATE_MOVE stateMove;
S4GTYPE typeLastCallFunc;
S4GVM_COMMAND vm_command;
GXBLEND blendSrcColor

Блоки, операции, отступы

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

Отступы в блоках {} равны одному значению табуляции (4 пробела), дополнительные отступы в блоках категорически запрещены.

Каждый символ открытия { и закрытия } блока должен быть расположен на новой строке.

Бинарные операторы окружаются двумя пробелами:

a + b

Унарные операторы пишутся без пробелов:

-2

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

Указатели и ссылки должны быть привязаны только к переменным:

int *a;
int &a;

В случае приведения типов, и при объявлении функций и методов, звездочка привязывается к имени типа:

int *a = (int*)b;
int* GetIntPtr();

Операции разыменования и взятие адреса должны оборачивать в скобки выражение:

&(aArr[0])
*(obj->GetPoint())

При вызове функции после имени функции сразу идет открывающая скобка.

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

Инициализация переменной всегда должны быть соответствующим типом, к примеру: float fNum = 1.0f; а не 1.0

Приведение типов неявное, если не требуется сделать это явно, либо потеря точности недопустима.

Если в операторе if, for, while, do...while находится выражение, занимающее больше одной строки, оно должно быть взято в скобки блока:

if(i > 1)
{
	for(int i = 0; i < 10; ++i)
	{
		printf("%d ", i);
	}
}

//Нельзя:
if(i > 1)
	for(int i = 0; i < 10; ++i)
	{
		printf("%d ", i);
	}

Примеры оформления конструкций

Оператор ветвления

if(i > 1)
{
	pIndices[iCurIdx++] = iStopIdx;
	pIndices[iCurIdx++] = iCurVtx;
	pIndices[iCurIdx++] = iCurVtx - 1;
}
else
{
	break;
}

Оператор множественного выбора

switch(pNode->Val->type)
{
case CVAR_STRING:
	printf("Default: \"%s\"\n", pNode->Val->default_val.c);
	break;
case CVAR_INT:
	printf("Default: \"%d\"\n", pNode->Val->default_val.i);
	break;
case CVAR_FLOAT:
	printf("Default: \"%f\"\n", pNode->Val->default_val.f);
	break;
case CVAR_BOOL:
	printf("Default: \"%s\"\n", pNode->Val->default_val.b ? "true" : "false");
	break;
default:
	printf("Default: none");
}

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

for(int i = 0; i < 10; ++i)
{
	printf("%d ", i);
}
int i = 0;
while(i < 10)
{
	printf("%d ", i++);
}
int i = 0;
do
{
	printf("%d ", i++);
}
while(i < 10);

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

Имена файлов рекомендуется писать относительно предметной области, без дополнительных префиксов проекта. Префиксы имени проекта необходимы для библиотек, h и cpp файлов прослоек библиотек (для предоставления функций по управлению функционалом библиотеки), файлов с main функцией, для четкой их идентификации и соотношения с проектом. Если в файле (cpp/h) описание одного класса - то файл называется как класс с точностью до регистра букв, если более одного класса, или не классы вовсе – то в соответствии со смыслом предоставляемого функционала. Рекомендуется в h файлах только заголовки, в cpp реализация. Заголовочные файлы должны содержать защиту от вложенного включения:

#idndef __ИМЯ_ФАЙЛА_H
#define __ИМЯ_ФАЙЛА_H

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

Классы, структуры, интерфейсы

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

Интерфейсы должны иметь только методы.

Классы могут иметь поля только в protected/private разделах.

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

Прочее

Использование goto не рекомендуется.

using namespace недопустимо.

Исключения из правил

  • типы данных которым префикс класса не применим, к примеру float3, Quaternion, matrix
  • дефайны, использование которых достаточно частое и необходимо максимально облегчить их запоминанием и написание, к примеру: mem_delete, mem_delete_a, mem_release

Документирование

Однострочный комментарий начинается с //! после пробела текст комментария.

Многострочный комментарий начинается с /*! после пробела текст комментария.

Метки:

  • note - заметка
  • warning - предупреждение
  • param - описание параметра, после метки следует пробел, затем название имя параметра из функции, а после, через пробел, описание
  • return - описание возвращаемого значения
  • deprecated - обозначение устаревшего кода
  • todo - сделать что-то
  • fixme - пepeдeлaть что-то

Метки могут быть только в многострочном комментрии.

Каждая метка начинается с новой строки, с пробела и с символа @ за которым следует название метки, затем через пробел текст метки. Метка deprecated может быть без текста.

Блок метки заканчивается окончанием строки, при этом метка может быть многострочной. Для многострочнйо метки в конце каждой строки необходимо использовать символ \ кроме последней строки, продолжение текста метки на новой строке должно начинаться с пробела (относительно положения названия метки).

Например:

/*! инициализация контекста
 @note В оконном режиме (windowed) можно указать произвольный размер окна, а в полноэкранном (fullscreen) допустимы только поддерживаемые режимы
 @note В область рендера будет растянута/сжата по размерам окна
 @param hWnd - нативный дескриптов окна
 @param iWidth - ширина области рендера в пикселях
 @param iHeight - высота области рендера в пикселях
 @param isWindowed - true-оконный режим, false-полноэкранный
*/
virtual BOOL initContext(SXWINDOW hWnd, int iWidth, int iHeight, bool isWindowed) = 0;