-
-
Notifications
You must be signed in to change notification settings - Fork 482
[UA] Правила кодування
- Загальні моменти
- Правила найменування
- Захист заголовків (header guards)
- Кінець файлу
- Умовна компіляція та директиви препроцесора
- Іменування файлів та обов’язковий вміст
Ширина відступу (indentation) — 4 пробіли.
Максимальна довжина рядка — 120 символів.
Відступ завжди становить один крок ширини (4 пробіли):
ПОГАНО
GatherInfo(expression, description, arg0, arg1, file, line,
function, assertionInfo);
ДОБРЕ
GatherInfo(expression, description, arg0, arg1, file, line,
function, assertionInfo);
Відкриваючі та закриваючі дужки секції мають бути на одному рівні:
ПОГАНО
if (lastErr==ERROR_SUCCESS) {
*buffer = 0;
return;
}
ДОБРЕ
if (lastErr==ERROR_SUCCESS)
{
*buffer = 0;
return;
}
Модифікатори доступу відступаються так само, як мітки goto — на рівні класу, без додаткового відступу:
ПОГАНО
class ObjectComparer
{
public:
ObjectComparer();
int Compare(const Object &a, const Object &b);
private: int InternalCompare(const Object &a, const Object &b);
};
ДОБРЕ
class ObjectComparer
{
public:
ObjectComparer();
int Compare(const Object &a, const Object &b);
private:
int InternalCompare(const Object &a, const Object &b);
};
Вміст простору імен не повинен мати відступів:
ПОГАНО:
namespace XRay
{
namespace Math
{
#define PI 3.14159265359
}
}
ДОБРЕ
namespace XRay
{
namespace Math
{
#define PI 3.14159265359
}
}
Якщо рядок дуже довгий і його потрібно розбити, продовження має мати відступ у один рівень (один shift-width):
ПОГАНО
if (lineLength>1 && (screenSize.Vertical<bufferSize.Vertical
|| explicitLines))
{
printf("this is a test section that will show how to handle "
"long lines, such as %s which is %d lines long",
"this", 2);
SetWindowText( hWnd,
"Button Name" );
}
ДОБРЕ
if (lineLength>1 && (screenSize.Vertical<bufferSize.Vertical
|| explicitLines))
{
printf("this is a test section that will show how to handle "
"long lines, such as %s which is %d lines long", "this", 2);
SetWindowText(hWnd, "Button Name");
}
if/for/while оператор, який займає більше одного рядка, завжди повинен мати дужки; те саме стосується блоку then/loop, якщо він займає більше одного рядка:
ПОГАНО
if (!ErrorAfterDialog)
MessageBox(NULL, "Fatal error occured\n\n"
"Press OK to abort program execution", "Fatal error",
MB_OK|MB_ICONERROR|MB_SYSTEMMODAL);
ДОБРЕ
if (!ErrorAfterDialog)
{
MessageBox(NULL, "Fatal error occured\n\n"
"Press OK to abort program execution", "Fatal error",
MB_OK|MB_ICONERROR|MB_SYSTEMMODAL);
}
Прототипи функцій мають бути відформатовані так само, як і виклики функцій:
ПОГАНО
void Debug::Backend(const char *reason,
const char *expression,
const char *arg0,
const char *arg1,
const char *file,
int line,
const char *function,
bool &ignoreAlways);
{
// function code
}
ПОГАНО
void Debug::Backend(const char *reason, const char *expression, const
char *arg0, const char *arg1, const char *file, int line, const char *
function, bool &ignoreAlways);
ДОБРЕ
// declaration
static void Backend(const char *reason, const char *expression,
const char *arg0, const char *arg1, const char *file, int line,
const char *function, bool &ignoreAlways);
// implementation
void Debug::Backend(const char *reason, const char *expression,
const char *arg0, const char *arg1, const char *file, int line,
const char *function, bool &ignoreAlways)
{
// function code
}
// if you need to comment parameters
void Debug::Backend(
const char *reason, // error reason
const char *expression, // failed expression
const char *arg0, // first argument
const char *arg1, // second argument
const char *file,
int line,
const char *function,
bool &ignoreAlways) // ignore errors of this type
{
// function code
}
Оператори switch повинні мати case на одному рівні відступу, без пробілу перед двокрапкою :
.
Якщо case займає один рядок, після двокрапки повинен бути один пробіл:
ПОГАНО
switch (vendor)
{
case Vendor::Intel :
...
case Vendor::AMD :
...
}
ДОБРЕ
switch (vendor)
{
case Vendor::Intel:
...
case Vendor::AMD:
...
}
ДОБРЕ
switch (controlId)
{
case IDC_TOGGLESTATS:
app->drawStats = !app->drawStats;
break;
case IDC_RESETCAMERA:
app->ResetCamera();
break;
case IDC_LIGHT_SIZE:
{
auto r = hud->GetSlider(IDC_LIGHT_SIZE)->GetValue()*0.01f;
app->spotLightObj->SetLightRadius(r);
break;
}
}
ДОБРЕ
switch (vendorId)
{
case 0x756e6547: vendor = Vendor::Intel; break;
case 0x68747541: vendor = Vendor::AMD; break;
default: vendor = Vendor::Unknown; break;
}
Немає пробілу між ім’ям функції та відкриваючою дужкою, немає пробілу між відкриваючою дужкою та першим параметром, після коми — один пробіл:
ПОГАНО
Msg ("hello %s\n", "world");
Msg( "hello world\n" );
Msg("hello world\n","world");
ДОБРЕ
Msg("hello world\n", "world");
Один пробіл після зарезервованих слів перед відкриваючою дужкою:
ПОГАНО
if(OnDialog)
ДОБРЕ
if (OnDialog)
Частина then
в операторі if повинна бути на окремому рядку.
Причина: це дозволяє налагоджувати if і бачити, коли він виконується.
ПОГАНО
if (OnDialog) OnDialog(true);
ДОБРЕ
if (OnDialog)
OnDialog(true);
Оператори else if
повинні бути на тому ж рівні відступу, що й початковий if
.
Причина: це схоже на структуру оператора switch
.
ПОГАНО
if (!strcmp(argv[1],"--help")) PrintUsage();
else if (!strcmp(argv[1], "--run")) {
RunApplication();
PrintResults();
} else PrintError();
ДОБРЕ:
if (!strcmp(argv[1], "--help"))
PrintUsage();
else if (!strcmp(argv[1], "--run"))
{
RunApplication();
PrintResults();
}
else
PrintError();
Оператори return
не повинні містити дужок і не повинні мати пробіл після них:
ПОГАНО
return (0);
ДОБРЕ
return 0;
ПОГАНО
return ;
ДОБРЕ
return;
Не використовуй зайві дужки в виразах:
ПОГАНО
if ((a!=b) || (c!=d))
...
ДОБРЕ
if (a!=b || c!=d)
...
Не виконуй виклик return
наприкінці функції, що повертає void
:
ПОГАНО
void foo()
{
bar();
return;
}
ДОБРЕ
void foo()
{
bar();
}
Не розділяй секції коду більше ніж одним порожнім рядком.
Оголошення класів/структур/енумів та ініціалізації повинні відкривати {
на наступному рядку:
ПОГАНО
struct Size {
int Width;
int Height;
};
ДОБРЕ
struct Size
{
int Width;
int Height;
};
ДОБРЕ (no members)
struct Dummy {};
ПОГАНО
Size size = {
LayoutHelper::AdjustLength(Clamp(length, 0, 1024)),
LayoutHelper::CalculatePreferredHeight(length, scaleFactor.y)
};
ДОБРЕ
Size size =
{
LayoutHelper::AdjustLength(Clamp(length, 0, 1024)),
LayoutHelper::CalculatePreferredHeight(length, scaleFactor.y)
};
ДОБРЕ (ініціалізація поміщається в один рядок)
Size size = {1024, 16};
Віддавай перевагу коментарям у стилі C++ (//
), а не стилю C (/* ... */
).
ДОБРЕ
/* draw overlay statistics */
DrawStats();
ДОБРЕ (better)
// draw overlay statistics
DrawStats();
Коментарі мають бути вирівняні по коду, до якого вони відносяться, або розташовані на один пробіл після кінця рядка.
ПОГАНО
/*
* draw overlay statistics
*/
DrawStats();
ПОГАНО
//
// draw overlay statistics
//
DrawStats();
ДОБРЕ
/* draw overlay statistics */
DrawStats();
ДОБРЕ (better)
// draw overlay statistics
DrawStats();
ДОБРЕ
DrawStats(); // draw overlay statistics
Коментарі, що займають більше одного рядка, мають дотримуватися наступних правил:
ПОГАНО
//
// last render stage: draw overlay engine performance statistics
// (input, render, sound, ai, physics)
//
DrawStats();
ДОБРЕ
// last render stage: draw overlay engine performance statistics
// (input, render, sound, ai, physics)
DrawStats();
Здоровий глузд повинен допомагати при виборі між циклами for або while.
ПОГАНО
int i = 0;
while (i<10)
{
i++;
...
}
ДОБРЕ
for (int i = 0; i<10; i++)
...
ПОГАНО
for (ptr = ptr->next; ptr; ptr = ptr->next)
...
ДОБРЕ
while (ptr = ptr->next, ptr)
...
У циклах for та while без тіла оператор повинен закінчуватися роздільником операторів (;
) на тому ж рядку.
ПОГАНО
for(i = 0; Test(i); i++)
;
ДОБРЕ
for (i = 0; Test(i); i++);
Ставте один пропуск перед і після оператора присвоєння.
ПОГАНО
int a=0;
x= x+1;
capacity*=2;
ДОБРЕ
int a = 0;
x = x+1;
capacity *= 2;
Не ставте пробіл перед роздільником операторів (;
), ставте один пробіл після нього.
ПОГАНО
for (i = 0 ;i<10 ;i--, j *= 2) ;
ДОБРЕ
for (i = 0; i<10; i--, j *= 2);
Не ставте пробіл після операторів інкременту (++
) та декременту (--
). Інкремент ставте після значення, а не перед ним.
ПОГАНО
i --;
++j;
ДОБРЕ
i--;
j++;
Тривіальні вирази з операторами >
, >=
, <
, <=
, ==
, !=
не повинні мати пробілів навколо них.
Приклади: a, array[i].var[j], sizeof(Foo), x+1
Вказівники (->
) не вважаються тривіальними виразами для операторів > >= < <=
, бо важко читати x->y>z
, тоді як x->y==z
читати легше.
ПОГАНО
if (x > 5)
ДОБРЕ
if (x>5)
ПОГАНО
if (x+1>5)
ДОБРЕ
if (x+1 > 5)
ПОГАНО
if (f(x, y) > g(y, z))
ДОБРЕ
if (f(x, y)>g(y, z))
ПОГАНО
if (x->y == 5)
ДОБРЕ
if (x->y==5)
ПОГАНО
if (x->y>=5)
ДОБРЕ
if (x->y >= 5)
Не збільшуй, не присвоюй і не змінюй значення змінної всередині виклику функції:
ПОГАНО
CalcXY(i++, 2);
ПОГАНО
SetX(i = 3);
ДОБРЕ (if i is not a global)
CalcXY(i, 2);
i++;
ДОБРЕ (if i is a global that CalcXY() uses)
i++;
CalcXY(i-1, 2);
ДОБРЕ
if (i++)
a[i++] = 4;
ДОБРЕ (if i is not a global)
i = 3;
SetX(i);
У циклах for, коли є функція, яка отримує наступний елемент, її слід викликати один раз (в умові кроку):
ПОГАНО:
for (int i = 0, ch = GetChar(); ch=='\r'; ch = GetChar(), i++)
HandleResult(ch);
ДОБРЕ:
for (int i = 0; (ch = GetChar())=='\r'; i++)
HandleResult(ch);
При присвоєнні у логічному виразі (if/for/while) використовуйте наступний шаблон, щоб уникнути попереджень компілятора:
ПОГАНО:
for (int i = 0; ch = GetChar(); i++)
HandleResult(ch);
if (x = ComputeNum())
return x;
ДОБРЕ:
for (int i = 0; ch = GetChar(), ch; i++)
HandleResult(ch);
if (x = ComputeNum(), x)
return x;
Під час ініціалізації рядка та встановлення нульового термінатора потрібно використовувати 0:
ПОГАНО:
string[0] = '\0';
if (string[3]=='\0')
{
}
ДОБРЕ:
*string = 0;
if (!string[3])
{
}
Правила іменування:
-
Обирайте легко читабельні імена ідентифікаторів. Наприклад, змінна
horizontalAlignment
зрозуміліша, ніжalignmentHorizontal
. -
Не використовуйте угорську нотацію, крім наступних випадків:
- Код, пов’язаний з UI, наприклад:
btnOpen
,lblMessage
,chkRecursive
,cbGameType
- Інтерфейсні класи:
IClient
,IGameLevel
,IGamePersistent
тощо - Типи шаблонів:
TBase
,TResult
- Код, пов’язаний з UI, наприклад:
Стилі написання імен:
-
класи/структури/перерахування:
PascalCase
- Математичні примітиви можуть бути у нижньому регістрі:
vector2f
,angle3f
,matrix44f
- Використання псевдонімів типів (using declarations) теж у нижньому регістрі:
uint
,int16
,uint64
- Математичні примітиви можуть бути у нижньому регістрі:
-
Функції:
PascalCase
-
Публічні та захищені поля:
PascalCase
- Математичні примітиви можуть використовувати
lowercase
:vector2f.x
,angle3f.yaw
,matrix44f.m03
- Математичні примітиви можуть використовувати
-
Приватні поля:
camelCase
-
Локальні змінні:
camelCase
-
Глобальні змінні:
PascalCase
-
Іменування просторів імен (namespaces):
PascalCase
Не додавайте ключове слово inline
для функцій, визначених у класі — такі функції автоматично є inline згідно зі стандартом.
При визначенні інтерфейсного класу деструктор слід оголосити чисто віртуальним (pure virtual) і додати його пусту inline-реалізацію після визначення класу:
ДОБРЕ
class IServer
{
public:
virtual ~IServer() = 0;
};
inline IServer::~IServer() {}
Не позначайте інтерфейсні класи атрибутами лінкування.
При перевизначенні віртуальної функції використовуйте специфікатор override
у її декларації.
ПОГАНО
class Server : public IServer
{
...
virtual void OnClientConnected(IClient *client);
...
};
ДОБРЕ
class Server : public IServer
{
...
virtual void OnClientConnected(IClient *client) override;
...
};
Перевірка значень, що повертаються функціями:
Функції, які повертають bool
або вказівник, будуть перевірятися без явного порівняння — достатньо перевірити, чи повернули вони true
або false
.
ПОГАНО
if (strstr(args, " -h")!=nullptr)
PrintHelp();
ДОБРЕ
if (strstr(args, " -h"))
PrintHelp();
ПОГАНО
if (IsUpdateRequired()==true)
Update();
ДОБРЕ
if (IsUpdateRequired())
Update();
ПОГАНО
cl = GetClient(id);
if (cl==nullptr)
return nullptr;
ДОБРЕ
cl = GetClient(id);
if (!cl)
return nullptr;
ПОГАНО
cl = GetClient(id);
if (cl!=nullptr)
Disconnect(cl);
ДОБРЕ
cl = GetClient(id);
if (cl)
Disconnect(cl);
При виділенні структури на стеку використовуйте нульове ініціалізування замість memset
:
ПОГАНО
ShaderParams params;
memset(¶ms, sizeof(params), 0);
ДОБРЕ
ShaderParams params = {};
За можливості, надавайте перевагу inline-функціям замість макросів:
ПОГАНО
#define RAD2DEG(angle) ((angle)*180/PI)
ДОБРЕ
template <typename T>
T RadiansToDegrees(T angle) { return angle*180/PI; }
Назви макросів зазвичай повинні бути у ВЕРХНЬОМУ РЕЄСТРІ, з таким самим форматуванням пробілів, як і в іншому коді:
ПОГАНО
#define RAD2DEG( angle ) ((angle)*180/PI)
#define RAD2DEG(angle) \
((angle) * 180 / PI)
ДОБРЕ
#define RAD2DEG(angle) ((angle)*180/PI)
ДОБРЕ
#define RAD2DEG(angle) \
((angle)*180/PI)
Звичайні макроси, які містять більше одного виразу, повинні бути загорнуті в конструкцію do...while(false). Це дозволяє безпечно використовувати їх всередині if...else конструкцій.
Приклад використання:
if (condition)
DO_A_AND_B;
else
DoSomethingElse();
ПОГАНО
#define DO_THIS_AND_THAT() \
{ \
DoThis(); \
DoThat(); \
}
ДОБРЕ
#define DO_THIS_AND_THAT() \
do { \
DoThis(); \
DoThat(); \
} while (false)
Не використовуйте форвардні оголошення (forward declarations), якщо це не є необхідним. Замість цього змініть порядок оголошень так, щоб викликаюча функція знаходилась нижче за ту, яку вона викликає (callee).
ПОГАНО
void Callee();
void Caller()
{
Callee();
}
void Callee()
{
}
ДОБРЕ
void Callee()
{
}
void Caller()
{
Callee();
}
Віддавайте перевагу переносимим типам даних із Common.hpp замість типів, специфічних для операційної системи.
ПОГАНО
BYTE b;
DWORD w;
ДОБРЕ
byte b;
uint32 w;
На початку файлу додайте захист від повторного включення. Не використовуйте include guards. Натомість використовуйте #pragma once
— це менш схильне до помилок і потребує менше коду для написання. Хоча це не частина стандарту, #pragma once
добре підтримується більшістю компіляторів.
ПОГАНО
#ifndef _XRAY_HPP_
#define _XRAY_HPP_
// The XRay.hpp content comes here
#endif // _XRAY_HPP_
ДОБРЕ
#pragma once
// The XRay.hpp content comes here
Файли повинні завершуватися порожнім рядком:
ПОГАНО
int main()
{
return 0;
}<EOF>
ДОБРЕ
int main()
{
return 0;
}
<EOF>
СКЛАДНІ секції з #if
повинні відповідати наступним рекомендаціям:
ПОГАНО
#ifndef NO_SINGLE
Msg("* Found new patch: %s", versionName);
#ifdef DOWNLOAD_UPDATES
#ifdef DOWNLOAD_UPDATES_GATHER_STATS
DownloadStats stats;
DownloadUpdate(downloadUrl, stats);
stats.Dump();
#else
DownloadUpdate(downloadUrl);
#endif
#endif
#endif
ПОГАНО
#ifndef NO_SINGLE
Msg("* Found new patch: %s", versionName);
# ifdef DOWNLOAD_UPDATES
# ifdef DOWNLOAD_UPDATES_GATHER_STATS
DownloadStats stats;
DownloadUpdate(downloadUrl, stats);
stats.Dump();
# else
DownloadUpdate(downloadUrl);
# endif
# endif
#endif
ДОБРЕ
#ifndef NO_SINGLE
Msg("* Found new patch: %s", versionName);
#ifdef DOWNLOAD_UPDATES
#ifdef DOWNLOAD_UPDATES_GATHER_STATS
DownloadStats stats;
DownloadUpdate(downloadUrl, stats);
stats.Dump();
#else
DownloadUpdate(downloadUrl);
#endif
#endif
#endif
Прості секції з #if
не повинні відступатися:
ДОБРЕ
#ifndef DEBUG
#ifdef _DEBUG
#define DEBUG
#endif
#ifdef MIXED
#define DEBUG
#endif
#endif
ПОГАНО
#ifndef DEBUG
#ifdef _DEBUG
#define DEBUG
#endif
#ifdef MIXED
#define DEBUG
#endif
#endif
ДОБРЕ
void Sleep(int milliseconds)
{
#ifdef WINDOWS
::Sleep(milliseconds);
#else
::sleep(milliseconds);
#endif
}
ПОГАНО
void Sleep(int milliseconds)
{
#ifdef WINDOWS
::Sleep(milliseconds);
#else
::sleep(milliseconds);
#endif
}
Після #endif
можна додати коментар, який вказує, до якого #if
він належить, якщо між #if
та відповідним #endif
є великий проміжок.
ПОГАНО
#ifdef _EDITOR
VerifyPath(path);
#endif // _EDITOR
ДОБРЕ
#ifdef _EDITOR
VerifyPath(path);
#endif
ДОБРЕ
#ifdef _EDITOR
// Lots of editor related code, that you really have to scroll down
// to see all of it.
#endif // _EDITOR
Використовуйте макрос defined()
лише тоді, коли у вас складний вираз. Якщо вам потрібно застосовувати defined()
для більш ніж одного прапорця, спробуйте об’єднати ці прапорці під одним новим прапорцем.
ПОГАНО
#ifndef DEDICATED_SERVER
#ifdef CONFIG_SHOW_LOGO_WINDOW
DestroyWindow(logoWindow);
#endif
#endif
ПОГАНО
#if defined(CONFIG_SHOW_LOGO_WINDOW)
DestroyWindow(logoWindow);
#endif
ДОБРЕ
#ifdef CONFIG_SHOW_LOGO_WINDOW
DestroyWindow(logoWindow);
#endif
ДОБРЕ (since you really need both flags)
#if !defined(DEDICATED_SERVER) && defined(CONFIG_SHOW_LOGO_WINDOW)
DestroyWindow(logoWindow);
#endif
Використовуйте using
замість typedef
:
ПОГАНО
typedef void (*FunctionType)(double);
typedef Vector3<float> vector3f;
ДОБРЕ
using FunctionType = void (*)(double);
using vector3f = Vector3<float>;
Використовуйте строго типізовані enum замість звичайних C enum:
ПОГАНО
enum CmdStatus
{
CmdStatusOk,
CmdStatusInProgress,
CmdStatusFailed,
};
ДОБРЕ
enum class CmdStatus
{
Ok,
InProgress,
Failed,
};
Перелічення (enum), які можуть бути серіалізовані, повинні мати призначені значення:
ПОГАНО
enum class CmdStatus
{
Ok = 1,
InProgress,
Failed,
};
ДОБРЕ
enum class CmdStatus
{
Ok = 1,
InProgress = 2,
Failed = 3,
};
Кожен рядок у enum повинен закінчуватися комою — це робить enum розширюваним. Комою слід не відокремлювати тільки останній рядок, якщо передбачається, що він ніколи не буде перевищений.
ПОГАНО
enum class CmdType
{
Reset = 1,
Load = 2,
Save = 3
};
ДОБРЕ
enum class CmdType
{
Reset = 1,
Load = 2,
Save = 3,
};
ДОБРЕ
enum class CmdType
{
Reset = 1,
Load = 2,
Save = 3,
Invalid = 0xFF
};
Розташовуйте вказівник (*
) та посилання (&
) поруч з ідентифікатором (іменем змінної):
ПОГАНО
IClient* GetServerClient();
void BanAddress(const IPAddress& ip);
ДОБРЕ
IClient *GetServerClient();
void BanAddress(const IPAddress &ip);
Розміщуйте static
/const
/volatile
/mutable
перед типом:
ПОГАНО
int const static z;
bool volatile exit;
int static Log(char const *s);
bool mutable lastState;
char const* const* name;
ДОБРЕ
static const int z;
volatile bool exit;
static int Log(char const *s);
mutable bool lastState;
const char *const *name;
Використовуйте виділення в стеку для локальних змінних з константним розміром. Динамічне виділення застосовуйте лише за потреби.
ПОГАНО
ConnectionParams *cp = new ConnectionParams();
...
delete cp;
ДОБРЕ
ConnectionParams cp;
Оператор delete
також обробляє nullptr
, тому немає потреби використовувати if ()
перед ним:
ПОГАНО (if str can be null):
if (str)
delete str;
ДОБРЕ:
delete str;
Константні рядки, що тривають більше ніж на один рядок, повинні закриватися лапками в кінці кожного рядка і відкриватися знову на наступному рядку. Пробіли між словами повинні залишатися в кінці рядка.
ПОГАНО
Log("Hello world, this is a long string that we want to print and
is more than 120 chars long so we need to split it");
ПОГАНО
Log("Hello world, this is a long string that we want to print"
" and is more than 120 chars long so we need to split it");
ДОБРЕ
Log("Hello world, this is a long string that we want to print "
"and is more than 120 chars long so we need to split it");
Функції, які не приймають жодних параметрів, слід визначати без використання void
:
ПОГАНО
IClient *GetServerClient(void);
ДОБРЕ
IClient *GetServerClient();
Тривіальні вирази з операторами +
, -
, *
, /
не повинні мати пробілів навколо них:
ПОГАНО
Foo(a + b);
ДОБРЕ
Foo(a+b);
ПОГАНО
Foo(2 * (a + b));
ДОБРЕ
Foo(2*(a+b));
ПОГАНО
Foo((a + b) / (1000 * 1000));
ДОБРЕ
Foo((a+b)/(1000*1000));
ПОГАНО
Foo((Min(aMin, bMin)+Max(aMax, bMax))*(width+Pow(a, p))/(1000*1000));
ДОБРЕ
Foo((Min(aMin, bMin)+Max(aMax, bMax)) * (width+Pow(a, p)) / (1000*1000));
Не вставляйте порожні рядки між кодом всередині функцій. Якщо хочете розділити фрагменти коду — використовуйте рядок з коментарем.
ПОГАНО
for (auto &item : items)
storage.push_back(item);
if (!storage.size())
Log("! ERROR: No items found");
ДОБРЕ
for (auto &item : items)
storage.push_back(item);
// check if there's no items
if (!storage.size())
Log("! ERROR: No items found");
Клас Foo
має бути у файлах src/Bar/Foo.cpp
і Foo.hpp
.
Усі файли повинні строго відповідати цьому прикладу.
Якщо не використовуються препроцесорні заголовки (precompiled headers), то в *.cpp
файлі першою має бути директива #include "Config.hpp"
, щоб конфігурація функцій впливала на всі інші файли. Якщо ж використовуються препроцесорні заголовки, #include "Config.hpp"
має йти відразу після них (наприклад, після stdafx.hpp
).
Заголовочні файли мають бути самодостатніми, тобто їх можна скомпілювати без залежності від інших включень.
Тому #include "Foo.hpp"
має бути одразу після Config.hpp
, щоб переконатися, що Foo.hpp
компілюється окремо без залежності від інших включень перед ним.
ДОБРЕ
Foo.hpp шаблон
#pragma once
#include "Config.hpp"
// ... Put here minimal includes required by Foo.hpp ...
// ... Put here your declarations ...
Foo.hpp шаблон
#include "Config.hpp"
#include "Foo.hpp"
// ... Put here minimal includes required by Foo.cpp ...
// ... Put here your code ...
ДОБРЕ (використання попередньо скомпільованих заголовків)
stdafx.hpp шаблон
#pragma once
#include "Config.hpp"
// ... Put here additional includes ...
Foo.hpp шаблон
#pragma once
#include "Config.hpp"
// ... Put here minimal includes required by Foo.hpp ...
// ... Put here your declarations ...
Foo.cpp шаблон
#include "stdafx.hpp"
#include "Config.hpp"
#include "Foo.hpp"
// ... Помістіть тут мінімальні include-файли, необхідні для Foo.cpp ...
// ... Помістіть сюди свій код ...
Використовуйте #include "Foo.hpp"
для хедерів у тій же директорії, що й вихідний файл.
Використовуйте #include "PathToFoo/Foo.hpp"
для хедерів в інших директоріях, де PathToFoo — шлях відносно кореневої директорії движка.
Використовуйте #include <Foo.hpp>
для зовнішніх системних файлів.
ПОГАНО
#include <Config.hpp>
#include <xrCore/xrCore.hpp>
#include "IReader.hpp"
#include "algorithm"
ДОБРЕ
#include "Config.hpp"
#include "xrCore.hpp" // we are in src/xrCore directory
#include "IO/IReader.hpp" // from src/xrCore/IO/IReader.hpp
#include <algorithm>
Вільна функція, що використовується в одному CPP-файлі: має бути реалізована як static, а оголошення у CPP-файлі додається лише, якщо функція використовується до реалізації.
Вільна функція, що використовується поза CPP-файлом (глобальна): має бути оголошена у HPP-файлі.
Клас/структура, що використовується в одному CPP-файлі: має бути оголошена всередині CPP-файлу.
Якщо потрібен вказівник поза CPP-файлом: у HPP-файлі має бути форвардне оголошення, а визначення — у C-файлі.
Якщо потрібні члени класу/структури поза CPP-файлом: оголосити їх у HPP-файлі.
Коментарі XXX
повинні бути у форматі <keywords>: <коментар>
. Якщо декілька назв — розділяти їх символом '/':
ПОГАНО
XXX: dima: optimize this case
XXX alexmx: RENDER check if already loaded
XXX alexmx: oles: move to common
ДОБРЕ
XXX: optimize this case
XXX dima: optimize this case
XXX alexmx RENDER: check if already loaded
XXX alexmx/oles: move to common
Home
English
- Русский
- Українська
- Беларуская
- Polski
- Český