Использование единого стиля кодирования обязательно при написании программ практикума. Конкретный стиль выбирается преподавателем практикума. Ниже приводится пример такого стиля.
1. Набор символов
1.1. В тексте программы запрещено использование любых управляющих символов, кроме символов “Перевода строки” LF (код 10) и “Возврата каретки” CR (код 13). К управляющим относятся символы с кодами от 0 до 31 и символ с кодом 127. Символ табуляции (код 9) можно использовать вместо восьми пробелов в отступах.
2. Отступы и ширина текста
2.1. Размер отступа — 2 символа.
2.2. Ширина текста программы (то есть количество символов в одной строке кода) не должна превышать 80 символов.
3. Имена
3.1. Имена глобальных переменных и функций должны быть осмысленными и отражать назначение. Слишком длинные имена, однако, не рекомендуются. В именах допускаются сокращения, которые не затрудняют понимание имени и назначения функций и переменных.
3.2. В именах должны использоваться только английские слова. Транслитерации русских слов нежелательны.
Например, имя функции f является недопустимым. Имена функций calculate_square_root и calc_sqrt допустимы, но последнее предпочтительнее, так как короче и использует общепринятые сокращения. Имя функции vychislenie_kornya нежелательно, так как использует русские слова.
3.3. Имена констант записываются полностью заглавными буквами. Если имя константы состоит из нескольких слов, для их разделения используются подчеркивания. Например, RED, POLL_INTERVAL.
3.4. Имена переменных, функций и меток записываются полностью строчными буквами. Если имя состоит из нескольких слов, для их разделения используются символы подчеркивания. Например, buf (допустимое сокращение от слова buffer), create_tree.
3.5. В именах не допускается использование каких-либо префиксов или суффиксов, отражающих тип объекта (т. н. венгерская нотация), например, a_crszkvc30LastNameCol.
4. Стиль отступов
4.1. Структурные типы
Определения структурных типов оформляются следующим образом:
struct StructureType { int field1; int field2; char *field3; };
или следующим образом:
typedef struct Node { struct Node *next; double data; } Node;
Каждое определение поля структуры записывается на отдельной строке. Не допускается объединять определение переменной и структуры, например, следующая запись недопустима:
struct Foo { int fudge; } foos[10];
4.2. Перечислимые типы
Определения перечислимых типов оформляются следующим образом:
enum Colours { RED, GREEN };
или следующим образом:
typedef enum Colours { RED, GREEN } Colours;
Допускается использование анонимных перечислений:
enum { READY_BIT = 0x1, ERROR_BIT = 0x2 };
Если определяется единственная константа, допускается запись анонимного перечисление в одной строке:
enum { BUFFER_SIZE = 1024 };
4.3. Указатели
При объявлении переменных указательного типа знак * относится к имени переменной, а не к имени типа. Пробел между * и именем переменной не ставится.
Правильно:
int *p; char *str, **pstr;
Неправильно:
int* p; int* q, r; char * * * s;
4.4. Инициализация
4.4.1. Инициализация составных типов оформляется так, чтобы была понятна структура инициализационных данных. Например:
int matrix[3][2] = { { 4, 5 }, { 10, 2 }, { 1, 1 } };
4.4.2. Инициализация простых и указательных типов записывается на той же строке, что и определение, например:
double summ = 0.0;
4.4.3. Инициализация символьных строк записывается, как правило, на той же строке, что и определение переменной.
char errmsg[] = "No error";
Если строка достаточно длинная, допускается разбивать инициализацию на несколько строк текста.
char *helpmsg = "hello: my first program\n" " usage: hello world\n";
4.4.4. Для инициализации локальных структур нулями используйте функцию memset.
4.4.5.
Если локальная переменная инициализируется сложным выражением (то есть не константой), каждое такое определение переменной должно записываться на отдельной строке.
Неправильно:
int var1 = some_func(params), var2 = some_other_func(params);
Правильно:
int var1 = some_func (params); int var2 = some_other_func (params);
4.5. Функции
4.5.1. Определение функции записывается следующим образом:
char * copy_str (const char *instr) { }
То есть тип возвращаемого значения, квалификаторы типа и классы памяти записываются на отдельной строке. Имя функции начинается с первой позиции, между именем функции и открывающей скобкой пробелы не ставятся. Открывающая и закрывающая фигурные скобки блока функции располагаются каждая на отдельной строке на первой позиции.
4.5.2. Если функция не принимает параметров, в списке параметров обязательно указание ключевого слова void.
int random (void) { }
4.6. Операторы
4.6.1. Оператор if без else записывается следующим образом.
if (test) { statements... }
Допускается опускать фигурные скобки, если тело оператора if содержит единственный оператор.
4.6.2. Оператор if с else записывается следующим образом.
if (test) { statements... } else { statements... }
4.6.3. Оператор while записывается следующим образом:
while (test) { statements... }
Допускается опускать фигурные скобки, если тело оператора while содержит единственный оператор.
4.6.5. Оператор do while записывается следующим образом:
do { statements... } while (test);
Допускается опускать фигурные скобки, если тело оператора do..while содержит единственный оператор.
4.6.6. Оператор for записывается следующим образом:
for (init; test; update) { statements... }
Допускается опускать фигурные скобки, если тело оператора for содержит единственный оператор.
4.6.7. Оператор switch записывается следующим образом:
switch (expr) { case LABEL1: statements... break; case LABEL2: { statements... break; } default: statements... break; }
4.6.8. Операторы вычисления выражения размещаются каждый на отдельной строке. Пример:
a = b; b = c;
4.6.9. Метки записываются с первой позиции вне зависимости от текущего отступа блока. Каждая метка записывается на отдельной строке.
void func (void) { for (...) { for (...) { } exit1:; } }
4.6.10. Использование оператора goto настоятельно не рекомендуется. Допускается использование оператора goto при обработке ошибок и при выходе из вложенных циклов. Допускаются только переходы вперед по тексту программы.
4.7. Операции
4.7.1. Бинарные операции +, * и пр. отделяются пробелами от аргументов, например,
a + b, a != 0, d >= a
4.7.2. Операции доступа к полю . и -> бинарной операцией не считаются, поэтому пробелами не окружаются. Скобки [, ] пробелами не окружаются. Примеры:
var.field, var->field, var->do_method(), arr[i][j]
4.7.3. После запятой во всех случаях и после точки с запятой в заголовке цикла for ставится один символ пробела.
int a, b, c = 0; printf("%d\n", n); for (i = 0; i < 10; ++i)
4.7.4. Между унарной операцией и операндом пробел не ставится. Примеры:
b = *a; i++; *p++ = 0;
4.7.5. Между именем функции и открывающей скобкой ставится один пробел.
printf ("%d\n", value); while ((c = getchar ()) != EOF);
4.7.6. После открывающей скобки и перед закрывающей скобкой пробел не ставится.
4.7.7. После закрывающей скобки операции приведения типов
ставится один пробел.
(unsigned char *) str
4.7.9. В выражении нежелательно ставить заведомо лишние скобки.
Неправильно:
if ((a > 0) && (!(b))) { }
Правильно:
if (a > 0 && !b) { }
5. Использование элементов языка и библиотек
5.1. В тексте программы нежелательно использование явных литералов целого и вещественного типов, не объявленных как константы, кроме следующих случаев:
- Константы 0 и 1 без ограничений.
- Константа 2, когда она обозначает файловый дескриптор потока ошибок.
- Константа -1 как специальное значение, сигнализирующее об ошибке.
5.2. Все определяемые константы должны иметь осмысленные имена. Для целочисленных констант предпочтительнее использовать анонимный перечислимый тип (enum).
5.3. Стандартные заголовочные файлы должны подключаться с помощью директивы
#include <FILE>
Пользовательские заголовочные файлы должны подключаться с помощью директивы
#include "FILE"
Неправильно:
#include "stdio.h" // стандартный заголовочный файл #include <tree.h> // пользовательский заголовочный файл
5.4. Все сообщения об ошибках, предупреждения, отладочные сообщения и прочая диагностическая информация, не являющаяся результатом работы программы в предположении корректных входных данных, должна выводиться на стандартный поток ошибок stderr.
5.5. Каждое диагностическое сообщение должно заканчиваться символом перехода на новую строку.
5.6. При выводе результата работы на стандартный поток вывода или в текстовый файл рекомендуется заканчивать вывод символом перехода на новую строку. Исключением являются программы, выполняющие посимвольную обработку потока данных.
5.7. Работа функции main должна заканчиваться выполнением оператора return с соответствующим кодом завершения. Код завершения — это число в диапазоне [0, 128).
5.8. Использование функций, не проверяющих переполнение буфера, допускается при условии корректного подсчета размера фактического буфера и размера требуемоей памяти. К таким функциям относятся sprintf, strcpy, strcat. Функцию gets запрещено использовать при любых обстоятельствах. Использование спецификатора %s функций scanf и fscanf без указания максимального количества вводимых символов запрещено.
5.9. В программе не должны присутствовать закомментированные строки кода, которые использовались для отладки.
5.10. Вспомогательные функции общего назначения (такие, как getline, функции работы со списками и т. д.) не должны ничего выводить на stdout или stderr. В случае возникновения ошибки такие функции должны, как правило, возвращать специальное значение.