(c) Larry Ewing, Simon Budig, Garrett LeSage
с 1994 г.

Кафедра Информатики и Математического Обеспечения

ПетрГУ | ИМиИТ | О кафедре | Проекты | Лаборатория ИТС | Семинары НФИ/AMICT
Сотрудники | Учебный процесс | Табель-календарь | Курсовые и выпускные работы
Вычислительные ресурсы | Публикации | Архив новостей | Контактная информация (English)

Стиль кодирования

Цели хорошего форматирования кода

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

  1. Точно представлять логическую структуру кода. Смысл форматирования — показать логическую структуру кода. Для демонстрации логической структуры программисты обычно применяют отступы и другие неотображаемые символы.
  2. Единообразно показывать логическую структуру кода. Некоторые стили форматирования состоят из правил с таким количеством исключений, что последовательно их соблюдать практически невозможно. Действительно хороший стиль подходит в большинстве случаев.
  3. Улучшать читабельность. Стратегия использования отступов, соответствующая логике, но усложняющая процесс чтения кода, бесполезна. Схема форматирования, использующая пробелы и разделители только там, где они требуются компилятору, логична, но читать такой код невозможно. Хорошая структура форматирования упрощает чтение кода.
  4. Выдерживать процедуру исправления. Лучшие схемы форматирования хорошо переносят модификацию кода. Исправление одной строки не должно приводить к изменению нескольких других.

Стиль форматирования

Базовый стандарт оформления кода: Kernighan & Ritchie (K&R)

Данный стиль использует стиль расстановки скобок при котором скобка переносится на новую строку при определении пространств имен (namespaces), классов (classes), функций, в остальных случаях скобка остается на той же строке, где располагается часть кода, к которой она (скобка) принадлежит. Отступ в данном стиле равняется 4-м пробелам.

Пример:

int foo(int is_bar) 
{
    if (is_bar) {
	bar();
	return 1;
    } else {
	return 0;
    }
}

Расстановка скобок как в стиле (K&R) соответствует формату явных блоков для управляющих структур.

Способы форматирования

Неотображаемые символы, к которым относятся пробелы, знаки табуляции, переводы строк и пустые строки, — это основное средство для демонстрации структуры программы.

Способ применения неотображаемых символов — группировка взаимосвязанных выражений, т.е. выделение связанных между собой конструкций в отдельный блок. Кроме необходимости группировать взаимосвязанные операторы, очень важно отделять несвязанные выражения друг от друга. Для этого можно использовать пустые строки. Они позволяют продемонстрировать организацию программы. Вы можете использовать их для деления групп взаимосвязанных операторов, отделения методов друг от друга и выделения комментариев.

Логический блок - группа подходящих друг к другу операторов. Отделяйте их друг от друга с помощью пустых строк.

Отступы применяются для демонстрации логической структуры программы. Как правило, операторы выделяются отступами, когда они следуют после некоторого выражения, от которого они логически зависят.

Скобки применяются для разъяснения выражений, состоящих из двух и более членов. Возможно, в скобках нет нужды, но они добавляют ясности в код.

Форматируйте блоки из одного оператора единообразно. Блоком из одного оператора называется единственный оператор, следующий за управляющей структурой. Причем форматирование с использованием скобок более предпочтително.

Пример:

if (expression) 
    один-оператор; 

if (expression) { 
    один-оператор; 
}

Форматирование строк, длина операторов/выражений

Старайтесь не превышать длину строки в 80 символов. Если аргументы функции не помещаются на одной строке, их следует разбивать на несколько строк.

Пример:

int lots_of_args(int an_integer, long a_long, short a_short, 
                 double a_double, float a_float);

В сложных выражениях размещайте каждое условие на отдельной строке.

Пример:

if ((('0' <= in_char) && (in_char <= '9'))
        ||  (( 'а' <= in_char) && (in_char <= 'z'))
        ||  (( 'A' <= in_char) && (in_char <= 'Z'))) {
    /* .... */
}

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

Пример:

total_bill = total_bill 
    + customer_purchases[customer_id] 
    + city_sales_tax(customer_purchases[customer_id]) 
    + state_sales_tax(customer_purchases[customer_id]) 
    + football_stadium_tax() 
    - sales_tax_exemption(customer_purchases[customer_id]); 

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

Пример (не нужное выравнивание):

    customer_purchases  = customer_purchases + customer_sales(customer_id); 
    customer_bill       = customer_bill + customer_purchases; 
    total_customer_bill = customer_bill + previous_balance(customer_id) + late_charge(customer_id); 

Всегда располагайте один оператор на строке. Это даст следующее:

  1. Точное представление о сложности программы.
  2. Если операторы расположены на отдельных строках, чтение кода происходит сверху вниз, без необходимости чтения слева на право.
  3. При размещении операторов на отдельных строках легко найти синтаксические ошибки, если компилятор сообщает только номера строк, где они произошли. При расположении нескольких операторов на одной строке ее номер ничего не скажет о том, какой оператор содержит ошибку.
  4. Когда строка содержит только один оператор, его легко редактировать — можно удалить или временно закомментировать всю строку.

Функции

Пример:

int function_one(int day_of_week, int day_of_month)
{
    /* body of function */ 
} 
int function_two(int param1, int param2, int param3,
               int param4)
{
    /* body of function */ 
} 

Операторы if/else, do, while

Расстановка скобок cоответствует формату явных блоков.

Пример:

if (x < foo(y, z)) {
   /* Body */
} 

Расставляйте скобки так, что бы не было "висячих" операторов else, лучше всегда выделять скобками блоки кода, даже когда скобки могут быть опущены. else if следует писать так:

Пример:

if (x == y) {
    ...
    
} else if (x > y) {
    ...
    
} else {
    ...
    
}

do / while следует писать так:

Пример:

do {
...

} while (condition);

Операции

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

Пример:

if (i == 0) {
    break;
}

a += 3;
a = b + c;

Не оставлять пробела после унарной операции.

Пример:

if (!flag) {
    break;
}

Правила именования

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

Начинайте каждый файл с комментария, информации о правах и лицензии:

/**
 *  file.h -- <BRIEF FILE DESCRIPTION>
 * <FILE DESCRIPTION>
 *
 * Copyright (c) <YEAR> <COPYRIGHT HOLDERS>
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 */
или более краткая версия:
/**
 *  file.h -- <BRIEF FILE DESCRIPTION>
 * <FILE DESCRIPTION>
 *
 * Copyright (c) <YEAR> <COPYRIGHT HOLDERS>
 *
 * This code is licensed under a MIT-style license.
 */

Комментарии описывают, что делает код, а не как, во всяком случае пока из кода можно легко понять его работу.

Заголовочные файлы

В заголовочный файл можно помещать следующее:

В заголовочном файле не должно быть:

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

Для того, что бы не проиcходило повторного включения заголовочного файла, включайте в него следующие инструкции:

#ifndef _MODULE_H_
#define _MODULE_H_
...
#endif // _MODULE_H_
Где MODULE - это имя заголовочного файла.

Настройка GNU Emacs

Если вы пользуетесь редактором GNU Emacs, то добавьте в файл ~/.emacs следующие строки для того, чтобы описанный в этом документе стиль использовался по умолчанию при редактировании исходного кода на языке C:

(add-hook 'c-mode-common-hook
          (lambda ()
            (c-set-style "linux")
            (setq c-basic-offset 4)))