Skip to content

Code style in project OpenPapyrus

sobolev edited this page Jun 7, 2020 · 8 revisions

Общие правила

Примеры кода

Декларация класса

//
// Descr: Комментарий к классу (первая строка)
//   продолжение комментария к классу на следующей строки с отступом в 2 пробела.
//
class Cls : public BaseCls {
public:
	Cls();
	int    MemberFunc01(long * pID, const void * pData, size_t dataLen);
	int    MemberFunc02(long id);
	const void * MemberFunc03(long id, size_t * pDataLen) const;
private:
	virtual void VirtualMemberFunc04(void * pItem);

	long   LastId;
};

Этот пример демонстрирует следующие особенности:

  • Наименования классов и структур начинается с прописной буквы
  • Наименования членов классов и структур так же начинаются с прописных букв
  • Открывающая скобка { для декларации находится на той же строке, что и наименование декларации
  • Ключевые слова public, private, protected для членов класса стартуют с той же позиции строки, что и ключевое слово class (struct, union, enum)

Определение функции (не ищите в ней смысл - это просто пример оформления текста)

int Foo(int paramA, double paramB, const void * pParamC, char * pParamD, WierdObject & rObj)
{
    int   ok = 1;
    int   local_var1 = 0;
    double local_var2 = 0.0; // простые типы крайне рекомендуется инициализировать при объявлении
    SomeObject * p_temp_obj = 0; // Указатель ОБЯЗАТЕЛЬНО инициализируется
    WierdObject & r_wobj = rObj;
    if(paramA > 0) {
        p_temp_obj = new SomeObject(pParamC);
        if(!p_temp_obj)
            ok = 0;
    }
    if(ok) {
        if(pParamD) {
            for(uint i = 0; i < 100; i++) {
                local_var2 += 0.002;
                pParamD[i] = (char)(local_var2 * 1.9);
            }
        }
        while(local_var2 > 0.0) {
            local_var2 -= 0.001;
        }
    }
    if(p_temp_obj && local_var1) do {
        p_temp_obj->Method(--local_var1);
    } while(local_var1 > 0);
    delete p_temp_obj; // Перед вызовами delete и free указатель никогда не проверяется на !0
    return ok;
}

Обратите внимание на следующие особенности:

  • Наименования аргументов функции: начинаются со строчной буквы, слова отделяются переходом от строчной к прописной букве. Аргументы-указатели всегда начинаются со строчной p (pParamC). Аргументы-ссылки всегда начинаются со строчной r (rObj).
  • Наименования локальных переменных: полностью состоят из строчных символов, слова разделяются подчеркиванием _ (local_var1). Локальные переменные указатели всегда начинаются с p_ (p_temp_obj). Локальные переменные-ссылки всегда начинаются с r_ (r_wobj).
  • В теле функции открывающие фигурные скобки всегда стоят в той же строке, что и оператор, требующий обрамления области его действия. Закрывающая фигурная скобка - всегда на отдельной строке.

Отступы

Для отступов в тексте кодов применяется символ табуляции. Кроме как в начале строки символы табуляции не должны нигде более использоваться (разделение между токенами внутри строки - только пробелы).

Операторы

Оператор if

    if(paramA > 0) {
        p_temp_obj = new SomeObject(pParamC);
    }

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

    if(paramA > 0) {
        for(uint idx = 0; idx < count; idx++) {
            ;
        }
    }

Конструкция if else

    if(paramA > 0) {
        p_temp_obj = new SomeObject(pParamC);
    }
    else {
        p_temp_obj = 0;
    }

Конструкция if do while

    if(c) do {
        foo(--c);
    } while(c);

Тот случай, когда простая вложенная в if конструкция не обрамляется фигурными скобками, и, более того, тело if начинается на той же строке (это действительно исключение: никогда иначе не ставьте оператор, выполняемый в случае if на той же строке - вносит путаницу при чтении кода).

    if(paramA > 0) p_temp_obj = new SomeObject(pParamC); // ТАК НЕЛЬЗЯ

Специальные макросы

В проекте часто используется целый ряд специальных макросов главным назначением которых является уменьшение кода и улучшение его читаемости. Большинство таких макросов определены в файле slib.h

oneof

Вместо конструкции if(a == 1 || a == 3) следует писать if(oneof2(a, 1, 3)) аналогично if(a == 1 || a == 3 || a == 8) следует писать if(oneof3(a, 1, 3)) В slib.h определены макросы от oneof2 до oneof14

SETIFZ

Вместо if(!a) a = b; следует писать: SETIFZ(a, b);

SETMAX

Вместо if(a < b) a = b; следует писать: SETMAX(a, b);

SETMIN

Вместо if(a > b) a = b; следует писать: SETMIN(a, b);

SETFLAG установка/снятие битовых флагов

Вместо if(a) flags |= f; else flags &= ~f; следует писать: SETFLAG(flags, f, a);

ASSIGN_PTR присваивание значения по указателю, если указатель не нулевой

Вместо if(p) *p = a; следует писать: ASSIGN_PTR(p, a);

RVALUEPTR присваивает значению величину, на которую ссылается указатель, если последний не равен нулю

Вместо if(p) a = *p; следует писать: RVALUEPTR(a, p);

Кроме того, макрос RVALUEPTR возвращает !0 если его второй аргумент (указатель) не равен нулю и ноль в противном случае. Этой особенностью можно пользоваться для альтернативной инициализации первого аргумента.

Например: if(!RVALUEPTR(a, p)) a = 0;