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

Материал из SkyXEngine wiki
Перейти к: навигация, поиск
м
Строка 319: Строка 319:
 
*типы данных которым префикс класса не применим, к примеру float3, Quaternion, matrix
 
*типы данных которым префикс класса не применим, к примеру float3, Quaternion, matrix
 
*дефайны, использование которых достаточно частое и необходимо максимально облегчить их запоминанием и написание, к примеру: mem_delete, mem_delete_a, mem_release
 
*дефайны, использование которых достаточно частое и необходимо максимально облегчить их запоминанием и написание, к примеру: mem_delete, mem_delete_a, mem_release
 +
 +
[[Category:Основы]]

Версия 07:39, 15 декабря 2018

Стандарт оформления кода (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
ui unsigned int
ui8 uint8_t
ui16 uint16_t
ui32 uint32_t
dw DWORD
w WORD
b, is, can, has, should is – является ли, can – может ли, has – имеет ли, should – должен ли bool
l long
ul unsigned long
a массив array
v вектор float2, float3, float4 и прочее
id идентификатор int32_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 
{};

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

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

enum COLOR {
  COLOR_RED,
  COLOR_GREEN,
  COLOR_BLUE
};

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

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

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

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

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

  • 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

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

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

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

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

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

a + b

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

-2

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

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

int *a;
int &a;

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

&(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) должны располагаться только в начале файла.

Прочее

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

Не рекомендуется переменные класса предоставлять в public.

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

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

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

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