Skip to content

Latest commit

 

History

History
133 lines (93 loc) · 7.84 KB

codestyle.md

File metadata and controls

133 lines (93 loc) · 7.84 KB

Coding Standards для языка Си

Форматирование программ

Отступы и скобочки

Строгих требований к расстановке отступов нет. Какой стиль хотите использовать - тот и используйте. Но нужно придерживаться следующих правил:

  • Код не должен выглядеть страшно.
  • Ширина кода вашей программы не должна превышать 76 символов. Изначально это требование было продиктовано особенностями текстовых терминалов (80х25 минус рамочки редактора), но и в современной жизни, даже на больших экранах, часто бывает нужно расположить два текста сравнения, либо перегружать экран вспомогательнымии окнами (отладчики etc.).
  • Отступы должны быть кратны 2-м пробелам.
  • Нельзя смешивать отступы пробелами и символы табуляции. Используйте что-то одно.

Объявление функций

На языке Си, в отличии от С++ или Java, принято выносить отделение возвращаемых типов функций и их модификаторов от названия на отдельную строку. Например, так:

static void
my_function(int arg1, char arg2, void *arg3)
{
    /* function body */
}

Во-первых, типы возвращаемых значений бывают достаточно длинными (вроде struct имя_структуры), да ещё и модификаторы на некоторых платформах встречаются вида extern __declspec(dllexport). В общем, тут трудно уложиться в положенные 76 символов.

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

Используемые типы данных

Для знаковых целочисленных типов данных используются короткие имена: char (8 бит), int (как правило, 32 бит). Всё. Никаких long long или short использовать не нужно. Есть замечательный заголовочный файл <stdint.h>, в котором перечислены типы данных с фиксированной точностью: int8_t, int16_t, int32_t, int64_t. Имена char и int являются общераспространенными синонимами для int8_t и int32_t, поэтому их использование не возбраняется за исключением особо экзотических случаев.

А вот использование ключевого слова long - строго запрещено, поскольку на разных платформах и компиляторах его размер разный.

Для беззнаковых типов данных нужно использовать только имена из <stdint.h>: uint8_t, uint16_t, uint32_t и uint64_t.

Обратите внимание, что char - это синоним понятия "байт", а вовсе не символ.

Объявления констант

Использование #define для объявления констант - строго запрещено!

Целочисленные константы нужно объявлять как перечисления:

enum {
    CONST_VALUE_1 = 1,
    CONST_VALUE_2 = 567,
    CONST_VALUE_3 = 890
};

Константы всех остальных типов данных - в стиле C++ по-Саттеру:

static const double PI = 3.14159;
static const char *PATH = "/usr/local";

Имена

Самое главное - учите simplified English. За транслит нужно расстреливать! Но и не злоупотребляйте редко используемыми словами, подобранными через multitran.ru. Всё-таки не исключено, что ваш код будут читать индусы или китайцы, для которых английский также не является родным языком.

На Си приняты безумно_длинные_имена_функций_или_пар_модуль_подчеркивание_метод, которые можно читать только в виде Python-style имен с подчеркиванием, но не CamelStyle. Для имен типов данных CamelStyle допустим, но не рекомендуется.

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

struct MyStruct {
    int  field_1;
    char field_2;
};

typedef struct MyStruct my_struct_t;

Для переменных давайте понятные имена на английском языке; не нужно делать однобуквенные сокращения. Исключение - общепринятые однобуквенные целочисленные переменные: N (именно заглавная буква, ибо традиция), i, j, k.

Используемые конструкции

Оператор goto

Всем известно, что оператор goto (дословный перевод на русский язык: иди_на) строго запрещён в промышленном программировании, а для языка Java - это вообще специально зарезервированное ключевое слово, которое приводит к ошибке компиляции.

Но в системном программировании допускается единственный случай, когда использование goto целесообразно: завершение работы функции при обработке ошибок, когда требуется гарантированно освободить некоторые ресурсы.

Пример:

int
my_function()
{
    char* memory  = calloc(BUFFER_SIZE, sizeof(char));
    int   fd_read = open(PATH, O_RDONLY);
    int   result  = NO_ERROR;

    /* ... something unimportant ... */

    if (/* error occured */ ) {
        result = SOME_ERROR_CODE;
        goto Function_End;
    }

Function_End:
    free(memory);
    close(fd_read);
    return result;
}

Во всех остальных случаях использовать оператор goto строго запрещено, как и в высокоуровневом программировании.

Массивы переменного размера

На языке Си, в отличии от C++, допускаются массивы переменного размера. Но использовать их можно только в том случае, если их размер заведомо предсказуем.

Вот так допустимо:

enum {N = 100};
char array[N];

Так тоже:

uint8_t N = /* some value, but not more 255 */;
char array[N];

А это - очень плохо:

int N;
scanf("%d", N); /* what if 9999999999999999999 at input? */
char array[N];