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

Материал из SkyXEngine wiki
Перейти к: навигация, поиск
(Имена в коде)
(Имена в коде)
Строка 110: Строка 110:
  
 
В именах переменных типа bool недопустимо использование отрицания.
 
В именах переменных типа bool недопустимо использование отрицания.
 
'''enum порождает префикс''' (опционально без префикса/постфикса названия enum'а), префикс можно сокращать до удобно читаемого/пишушегося названия. Примеры:
 
<syntaxhighlight lang="C++">
 
NPC_STATE_MOVE stateMove;
 
S4G_TYPE typeLastCallFunc;
 
S4G_VM_COMMAND vm_command;
 
GXBLEND blendSrcColor
 
</syntaxhighlight>
 
  
 
'''Имена типов/классов/структур''', должны быть обязательно написаны в смешанном регистре, начиная с верхнего: CPoint, CCamera
 
'''Имена типов/классов/структур''', должны быть обязательно написаны в смешанном регистре, начиная с верхнего: CPoint, CCamera
Строка 149: Строка 141:
 
</syntaxhighlight>
 
</syntaxhighlight>
  
'''Дефайны и перечисления''' должны быть написаны только в верхнем регистре с использованием нижнего пробела: OBJ_MAX_LEN
 
 
Константы в перечислениях должны иметь префикс - общее имя типа, при этом название перечисления должно совпадать с префиксом:
 
<syntaxhighlight lang="C++">
 
enum COLOR {
 
  COLOR_RED,
 
  COLOR_GREEN,
 
  COLOR_BLUE
 
};
 
</syntaxhighlight>
 
 
Если определение дефайна должно вставляться в выражения, то оно должно оборачиваться в скобки:
 
<syntaxhighlight lang="C++">#define A_ADD_B(a, b) (a + b)</syntaxhighlight>
 
иначе если определение дефайна является конечной инструкцией, оно должно быть обернуто в фигурные скобки:
 
<syntaxhighlight lang="C++">#define PRINT(str) {printf(str);}</syntaxhighlight>
 
  
 
Настоятельно рекомендуется использование симметричных имен:
 
Настоятельно рекомендуется использование симметричных имен:
Строка 182: Строка 159:
 
*show/hide,  
 
*show/hide,  
 
*suspend/resume
 
*suspend/resume
 +
 +
===define и enum===
 +
 +
'''define и enum''' создают константы, поэтому должны быть написаны только в верхнем регистре с использованием нижнего пробела: OBJ_MAX_LEN. При этом имена enum пишутся слитно с префиксом (например: GXTEXTURE_ADDRESS_MODE), а имена define с разделением (например: GX_MAX_SAMPLERS).
 +
 +
Константы в перечислениях должны иметь префикс - общее имя типа, при этом название перечисления должно совпадать с префиксом:
 +
<syntaxhighlight lang="C++">
 +
enum COLOR {
 +
  COLOR_RED,
 +
  COLOR_GREEN,
 +
  COLOR_BLUE
 +
};
 +
</syntaxhighlight>
 +
 +
Если определение дефайна должно вставляться в выражения, то оно должно оборачиваться в скобки:
 +
<syntaxhighlight lang="C++">#define A_ADD_B(a, b) (a + b)</syntaxhighlight>
 +
иначе если определение дефайна является конечной инструкцией, оно должно быть обернуто в фигурные скобки:
 +
<syntaxhighlight lang="C++">#define PRINT(str) {printf(str);}</syntaxhighlight>
 +
 +
'''enum порождает префикс''' (опционально без префикса/постфикса названия enum'а), префикс можно сокращать до удобно читаемого/пишушегося названия. Примеры:
 +
<syntaxhighlight lang="C++">
 +
NPC_STATE_MOVE stateMove;
 +
S4G_TYPE typeLastCallFunc;
 +
S4G_VM_COMMAND vm_command;
 +
GXBLEND blendSrcColor
 +
</syntaxhighlight>
  
 
== Блоки, операции, отступы ==
 
== Блоки, операции, отступы ==

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

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

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

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


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

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

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

Имена в коде

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

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

Префикс fn используется для переменной указателя который ссылается на функцию.

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

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

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

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

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

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

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

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

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

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

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

vector<Point>  aPoints;

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

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

namespace gdata 
{};


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

  • 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

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;
S4G_TYPE typeLastCallFunc;
S4G_VM_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;