вторник, 26 января 2016 г.

Порядок в коде – порядок в голове

Ещё одна статья от нашего друга ice, стиль авторский.

Хочу поговорить об оформлении кода, я считаю что если код правильно оформлен, то это уже заведомо хороший код. Если в вашем коде нет определенного стандарта и каждый ваш исходник оформляется по разному, то вы в скором времени не сможете просто прочитать свой код. При написании больших проектов вскоре вы забываете что писали, и смотрите на код будто на чужой.

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

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

Оформление кода я покажу на примере, так как лучше один раз показать, чем писать кучу букв тут. Данное оформление справедливо только для “cи” кода,
и оно хорошо применимо для любой платформы.

#ifndef __VFS__
#define __VFS__

#include <types.h>
#include <logger.h>

BOOLEAN
VfsAddModuleNative(
    CHAR *pName);

#endif
BOOLEAN
VfsAddModuleNative(
    CHAR *pName)
{

    BOOLEAN Result;
    CHAR Name[260];
    VOID *pModule;
    VOID (*InitPlugin)();

    Result=FALSE;
    sprintf(Name,"%s/%s.so",LIBPATH,pName);
    pModule=dlopen(Name,RTLD_LAZY);
    ASSERT(pModule);

    if (pModule)
    {

        sprintf(Name,"init%s",pName);
        InitPlugin=dlsym(pModule,Name);
        ASSERT(InitPlugin);

        if (InitPlugin)
        {

            InitPlugin();
            Result=TRUE;

        }

    }

    return Result;

}

Итак каких же стандартов я придерживаюсь в таком коде?

  1. Типы записываются в верхнем регистре
  2. Имена переменных, и всех ключевых слов начинаются с заглавной буквы
  3. Тип в именах переменных указывается только для указателей, pData или ppData (остальные типы считаю указывать избыточным)
  4. Все элементы функции (тип, имя, аргументы) начинаются с новой строки
  5. Между кодовыми блоками ({}) ставятся переносы строки
  6. Функции которые предполагается включать в заголовочные файлы, должны начинаться с имени “.с” файла (VfsSomeFunction)
  7. Функции которые не используются в интерфейсах, должны быть определены как static, что бы не захламлять пространство имен
  8. В заголовочных файлах использовать конструкции #ifndef __VFS__ #define __VFS__, в имени участвует имя модуля
  9. Переменные с именем в один литерал (i,j и т.д.) записываются в нижнем регистре
  10. Имена макросов записываются в верхнем регистре
  11. Весь код должен быть пронизан ASSERT
  12. Кодовые блоки ({ или }) или ключевые слова, начинаются всегда с новой строки
  13. Глобальные переменные именуются с “g_”, например g_SomeVariable
  14. Глобальные переменные не должны находиться в хидерах, если нужно передать такую переменную в другой модуль, то использовать для этого функцию

Так как код планируется кросплатформенный, то хорошо бы определиться с типами, так как если брать windows, то 4-байтную переменную можно определить кучей типов DWORD, UINT и еще не весть что.

Так как структуры планируется именовать в верхнем регистре то у меня создан такой файлик

#ifndef _TYPES_
#define _TYPES_

#include <stdio.h>
#include <stdlib.h>

#define TRUE 1
#define FALSE 0
typedef char CHAR;
typedef unsigned char UCHAR;
typedef short SHORT;
typedef unsigned short USHORT;
typedef int INT;
typedef unsigned int UINT;
typedef long LONG;
typedef unsigned long ULONG;
typedef long long LONG64;
typedef unsigned long long ULONG64;
typedef int BOOLEAN;
typedef void VOID;
typedef size_t SIZE_T;
#define CONST const
#define IN
#define OUT
#define OPTIONAL

#endif

Тут заданы все необходимые простые типы, которые могут вам понадобиться и все в едином стандарте (верхний регистр)

Отдельный заголовочный файл для отладочных сообщений

#ifndef _LOGGER_
#define _LOGGER_

#ifdef _DEBUG_

#include <string.h>
#include <unistd.h>

#define LOG(pSpec, ...)                                             \
{                                                                   \
    CONST CHAR* pFile = strrchr(__FILE__, '\\');                    \
    printf("[PID:%5u]R3:%s!%s(%u): "pSpec"\n",                      \
        (int)getpid(),                                              \
        pFile?pFile+1:__FILE__,                                     \
        __FUNCTION__,                                               \
        __LINE__,                                                   \
        ##__VA_ARGS__);                                             \
}

#define LOG_INFO(pSpec, ...) LOG("INFO: " pSpec,##__VA_ARGS__)
#define LOG_ERROR(pSpec, ...) LOG("ERROR: " pSpec,##__VA_ARGS__)
#define LOG_DEBUG(pSpec, ...) LOG("DEBUG: " pSpec,##__VA_ARGS__)

#define ASSERT_F(Condition,pMessage,...)                            \
{                                                                   \
    if (!(Condition))                                               \
    {                                                               \
        LOG("ASSERT FAILED "pMessage,##__VA_ARGS__);                \
        /*__asm__ volatile("int $0x03");*/                          \
    }                                                               \
}

#define ASSERT(Condition) ASSERT_F(Condition,"")

#else

#define LOG(pSpec,...)
#define LOG_INFO(pSpec, ...)
#define LOG_ERROR(pSpec, ...)
#define LOG_DEBUG(pSpec, ...)
#define ASSERT_F(Condition,pMessage,...)
#define ASSERT(Condition)

#endif


#endif

Многие не используют ASSERT в своих программах, а используют отладочные сообщения. Но это не всегда оправдано, вот например возьмем код выше, и перепишем его в виде логирования с отладочными сообщениями

pModule=dlopen(Name,RTLD_LAZY);

if (pModule)
{

}
else
{
    LOG_ERROR("Все пошло не так как хотели!!!!");
}

Нам пришлось ввести конструкцию else, которая создает лишний код, и когда мы сделаем релиз, то код с else останется.

Да и это некрасивый код. Гораздо приятнее он выглядит с ASSERT, в нем сразу реализовано это условие проверки, что если не так. То логирует номер строки и имя файла, и не нужно выдумывать сообщение о падении, все кратко и просто.

Запись Порядок в коде – порядок в голове впервые появилась VxLab.



from VxLab http://ift.tt/1KEqgFg
via IFTTT

Комментариев нет:

Отправить комментарий