CodingStyle

Требования к оформлению исходных текстов программ на языке программирования C/C++

Ширина экрана 80 символов

Строки кода длиной больше 80 символов разбиваются на несколько строк.

int TopoMPI_Allgather(void **sendbuf, int *sendcount, MPI_Datatype *sendtype,
                      void **recvbuf, int *recvcount, MPI_Datatype *recvtype,
                      MPI_Comm *comm)
{
    allgather_ptr = topompi_select_allgather(topompi_comm,
                                             *recvcount, *recvtype);
    if (allgather_ptr != NULL) {
        return (allgather_ptr)(*sendbuf, *sendcount, *sendtype, *recvbuf,
                               *recvcount, *recvtype, *comm, topompi_comm);
    }
    fprintf(stdout, "The quick brown fox jumps over the lazy dog. "
                    "The quick brown fox jumps over the lazy dog.\n"
                    "The quick brown fox jumps over the lazy dog - %d", 2);
}

Расстановка операторных скобок и отступов

Следует делать отступ в 1 символ табуляции или 4 пробела в теле каждого составного оператора, при описании полей структур, членов классов и перечислений. При описании циклов, ветвлений, классов, структур и перечислений открывающаяся фигурная скобка размещается на той же строке (стиль “K&R”).

enum {
    FILESIZE_MAX = 1024
};

struct user {
    char *name;
    int key;
} userstab[] = {
    {"foobar", 0},
    {"nobody", 2},
    {NULL, 0}
};

int main()
{
    int data;
    double eps;
    int vlas[4] = {-4, 1, 2, 6};
    double dx[3] = {
        13.1492,
        -4.5667,
        34.4716
    };

    if (process_rank == 0) {
        sprintf(filename, "%s.%d", getenv("LOG_FILE"), process_rank);
        process_env();
    }

    if (issymbol) {
        /* ... */      
    } else if (isnumeric) {
        /* ... */      
    } else if (ishex || islogical) {
        /* ... */      
    } else {
        /* ... */      
    }

    while (diff < eps) {
        /* ... */
    }

    for (i = 0; i < nelems; i++) {
        /* ... */
    }

    for (;;) {
        /* Infinite loop */
    }

    switch(ch) {
        case 'a':
        case 'b':
        case 'c':
            isabc = 1;
            break;
        case '0':
            iszero = 1;
            break;
        default:
            isunknown = 1;
    }

    do {
        /* ... */    
    } while (diff < eps);

    return 0;
}

Расстановка пробелов

Бинарные операторы (=, +, -, *, /, %, &&, ||, ^, |, &, ==, >, <, >=, <= и др.) обрамляются пробелами слева и справа. Между унарным оператором и его операндом пробел не ставится. После запятой всегда ставится пробел.

int fun(int a, int b, int c)
{
    int x = 2, y, z = 5;

    x += y - z / (a - b) * (-c) % -b;
    if (x >= a || z == 0) {
        isfound = 1;
    }
    printf("Value x = %d / %d", a, b);
    return --x / y++;
}

При объявлении указателей и их разыменовании символ * размещается у идентификатора без пробела.

void *xdata(int size, void *buf)
{
    struct user *p;
    struct graph *g;
    int *vals = NULL;
    double *deps;

    vals = (int *)malloc(10 * sizeof(*vals));
    p = (struct user *)buf;
    g->vertices[5 + vals[0]] = 1;
    *deps = 0.45;
}

Объявление и определение функций

Рекомендуется начинать определение функции с комментария. В начале функции следует размещать блок с определением всех переменных и пустую строку, отделяющую блок от кода.

/* open_log: Open log and return 0 on success */
int open_log(char *filename, int level)
{
    int val;
    char *buf;

    /* do something */  
    return 0;
}

/*
 * app_error: Prints an error message and terminates processes.
 */

void app_error(MPI_Comm comm, const char *format, ...)
{
    va_list ap;
    static char buf[ERROR_BUF_MAX];

    va_start(ap, format);
    vsprintf(buf, format, ap);
    va_end(ap);

    fprintf(stderr, "app: error: %s\n", buf);
    MPI_Abort(comm, 1);
    exit(EXIT_FAILURE);
}

Макроопределения

Имена макроопределения следует набирать в верхнем регистре.

#define NELEMS(x) (sizeof(x) / sizeof(x[0]))
#define BUFSIZE_MAX 1024

Для констант рекомендуется использовать не макроопределения, а перечисления – @enum@.

Комментарии

Однострочные и многострочные комментарии оформляются следующим образом.

/* Однострочный комментарий */

/*
 * Многострочный комментарий
 * ...
 */

Организация c-файла

1. Комментарий к файлу. 2. Включение заголовочных файлов стандартной библиотеки C. 3. Включение системных заголовочных файлов. 4. Включение заголовочных файлов программы. 5. Макроопределения. 6. Определение перечислений, типов, структур, констант, глобальных переменных. 7. Объявление функций. 8. Определение функций.

Группы объявлений разделяются пустой строкой.

/*
 * parser.c: SAX XML Parser.
 *
 * (C) 2007-2010 Ivan Ivanov <foo@bar.org>
 */


#include <stdlib.h>
#include <math.h>

#include <linux/types.h>

#include "myxml.h"
#include "print.h"

#define NLEN 100
#define XMALLOC(size) malloc(size)

enum NodeType {
    ROOT_NODE = 0,
    LEAF_NODE = 1,
    INTERNAL_NODE = 2
};

typedef struct xmlnode xmlnode_t;
struct xmlnode {
    char *name;
    void *data;
    int key;
};

const char *libname = "SXP";

int xmlparser_ncalls;
xmlnode_t *rootnode = NULL;

void xmlparser_open(char *filename);
int xmlparser_traverse(xmlnode_t);

int main(int argc, char **argv)
{
    /* ... */
    return 0;
}

void xmlparser_open(char *filename)
{
    /* ... */
}

int xmlparser_traverse(xmlnode_t)
{
    /* ... */
}

Организация заголовочных h-файлов

1. Комментарий 2. "Стражи повторного включения" 3. Включение заголовочных файлов стандартной библиотеки C. 4. Включение системных заголовочных файлов. 5. Включение заголовочных файлов программы. 5. Макроопределения. 6. Определения перечислений, типов, структур, объявления функций.

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

/*
 * printlib.h: PrintLib library header file.
 *
 * (C) 2009-2010 Ken Bangl <ken@bbcix.net>
 */


#ifndef PRINTLIB_H
#define PRINTLIB_H

#include <sys/time.h>
#include <stdio.h>

#ifdef __cplusplus
extern "C" {
#endif

#define IFSET(flag, command) if (flag) { command; }
#define TIMERON(timer) { timer_on(&(timer)); }
#define TIMEROFF(timer) { timer_off(&(timer)); }

enum {
    ALLGATHER_TAG = 128,
    ISEND_TAG
};

/*
 * Hierarchical computer system description
 */

typedef struct topompi_commlevel topompi_commlevel_t;
struct topompi_commlevel {
    int nnodes;
    int is_channels_uniform;   /* Channels on one level is uniform */
    int msgsize_log2_start;    /* log2(first message size in table) */
    int msgsize_log2_end;      /* log2(last message size in table) */
    int *txtime;
};

extern topompi_compsys_t *topompi_compsys;
extern const char *topompi_compsys_config_file;
extern char topompi_nodename[];     /* Processor name of local process */
extern int topompi_process_rank;    /* Rank of local process in world */

/* Global variables (from environment) */
extern int topompi_debug;
extern int topompi_allgather_alg;

void topompi_initialize();
void topompi_finalize();

topompi_commlist_t *topompi_commlist_create();
int topompi_commlist_delete(topompi_commlist_t *commlist, MPI_Comm comm);

#ifdef __cplusplus
}
#endif

#endif /* TOPOMPI_IMPL_H */

Именование переменных и функций

Имя переменной должно отражать её содержимое.

  • schedule - расписание
  • task - задача
  • job - задание
  • tastset - набор задач
  • process - процесс, ветвь программы
  • rank - ранг
  • ncalls, calls_count - количество вызовов
  • userno, usernum - номер пользователя
  • avgtime, time_avg - среднее время
  • msgsize - размер сообщения
  • isclosed - флаг, указывающий закрыт ли файл
  • graph, g - граф
  • s, str - строка
  • funptr, fun_ptr - указатель на функцию
  • vertices - массив вершин
  • points - массив точек
  • procs, processes - массив или список процессов
  • filename - имя файла
  • sendbuf, sbuf - буфер с данными для отправки
  • tmpbuf - временный буфер
  • optype - тип операции
  • nblocks - количество блоков
  • rc, res - результат, код возврат
  • prev - предыдущий
  • next - следующий
  • data – данные

Если переменная глобальная, то она может включать префикс библиотеки или программы.

int proflib_nactiveusers = 0;
char *vim_filename = NULL;

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

graph_t *proflib_graph_create(int nvertices);
FILE *logger_open(char *filename);
void logger_close(FILE *flog);
void geomlib_tree_addnode(int nodeval, int key);
int geomlib_is_balanced_tree(struct tree *tree);

Словарь:

  • open, init, create, load - открыть, инициализировать, создать, загрузить
  • close, free, destroy, save, clean - закрыть, освободить, уничтожить, сохранить, очистить
  • add, insert, append, push - добавить, вставить, присоеденить, втолкнуть
  • delete, remove, pop, erase
  • set/get - установить, получить
  • search, lookup, find - искать, найти
  • process, do, execute - обработать
  • generate, compute, calculate, build - сгенерировать, построить
  • first/last, - первый последний
  • show/hide - показать, спрятать
  • suspend/resume - приостановить, возобновить