"Код программы надо писать так, чтобы он был понятен без комментариев." Это правда. Следование описанным ранее рекомендациям должно сделать ваши программы более понятными. Однако для описания прототипа функции, логики её работы или обоснования принятого при реализации решения требуются словесные пояснения. Такие пояснения можно разделить на два типа.
Технически и комментарий и документация могут быть оформлены
как комментарий в смысле языка программирования (строка,
заключенная в /* ... */
). Разница
содержательная. Документация относится к функции целиком и должна
описывать что она делает и как ей пользоваться. После прочтения
документации у читателя не должно возникать желания посмотреть
исходный код, чтобы понять, например, какой ответ вернет функция
при поступлении "нестандартных" входных данных. Это все должно
быть описано в документации.
Комментарии, в отличие от документации, поясняют сложные фрагменты в реализации функции. Это подсказка человеку, который читает исходный код самой функции. Безусловно, такой программист прочитает и документацию, например, чтобы получить представление о том, что эта функция должна делать.
Далее мы поговорим о том, что и как нужно комментировать и документировать.
Начнем с документирования. Документирование является обязательным. Вообще говоря, не только каждая функция, но и каждый .c и .h файл должен иметь описание. Документирование файлов имеет значение при разработке крупных систем и мы его не будем сейчас касаться.
Документация прототипа функции должна включать:
Рассмотрим в качестве примера функцию циклического сдвига массива.
/**
** Циклический сдвиг массива на k позиций.
**
** Параметры:
** array: массив целых чисел.
** length: длина массива array.
** k: величина сдвига.
**
** Массив array сдвигается на k позиций. Если значение k положительное, то злементы массива сдвигаются
** вправо (в сторону увеличения индексов), а последние k элементов переносятся в начало массива:
** abcd -> dabc.
** При отрицательном k элементы сдвигаются влево:
** abcd -> bcda.
** Если k > length, то сдвиг проиводится на (k mod length) позиций.
**
** Возвращаемое значение:
** В случае успеха функция возвращает 0. Любое другое значение является кодом ошибки.
**
** Элементы массива array изменяют свой порядок.
**
** Метод:
** Используется метод обращения частей массива, который имеет алгоритмическую сложность O(length).
*/
int cyclic_shift(int *array, unsigned int length, int k);
Имеет смысл писать документацию функции до того, как вы начали её реализовывать. Это поможет вам понять, что вы собираетесь сделать. Очень часто на вопрос "Что делает такая-та функция в Вашей программе?" студенты начинают говорить: "Она в цикле перебирает все ...". Это ответ на вопрос "Как она это делает?" путем "подстрочного перевода с Си на русский". Правильный ответ может быть: "Обращает матрицу", "Находит максимальное значение в массиве".
Различие между прототипом и реализацией — это различе между что и как. Документация реализации может включать более подробное описание метода решения. Эта информация важна для человека, который чистает .c-файл.
"Не баг, а фича!" (распространенное выражение). Если при некоторых входных данных программа выдает неадекватный ответ, и такое поведение не описано в документации, то это считается ошибкой программы ("багом"). Если же в документации сказано, что "так делать нельзя", то поведение считается корректным ("фичей").
Наличие комментариев в программе не является обязательными. Комментариями можно снабжать имена переменных, сложные фрагмены кода, логическую часть (например, при решении системы линейных уравнений указать, что дальше выполняется обратный ход метода Гаусса).
Комментарии должны касаться сути, а не опраторов языка программирования. Такой комментарий
k = k + 1; // Увеличиваем k на единицу
абсолютно бесполезен. Любой человек, который знает язык Си,
понимает, что делает этот оператор. Более полезным может быть комментарий следующего вида.
k = k + 1; // Переходим к следующей строчке матрицы
Если же при объявлении переменной будет сказано, что она
соответствует номеру сроки матрицы, или же её название будет не k
,
а line
, то комментарий будет и в этом случае лишним.
Это нормально, если документация занимает больше места, чем сама функция.