CHAP2-4 (1018803), страница 3
Текст из файла (страница 3)
// В точке 1 алгоритм устанавливается на ...
//
here_is_the_code();
while ( some_condition )
{
this_code_is_rather_obscure(); /* 1 */
}
more_stuff_here();
while ( some_condition )
{
this_code_is_also_obscure(); /* 2 */
}
29. Комментарии должны быть выровнены вертикально.
Выравнивайте начало и конец комментария вертикально в многострочных комментариях.
/* Первая строка,
* вторая строка,
* третья строка.
*/
Если ваш компилятор их поддерживает, то здесь помогут комментарии в стиле С++:
// Первая строка,
// вторая строка,
// третья строка.
Есть две причины появления этого правила, они обе демонстрируются в последующей программе:
/**********************************************************
void the_function( void )
Это многострочный комментарий, выполняющий все, что должен делать комментарий.
К сожалению, отсутствие слева вертикального столбца из звездочек затрудняет зрительное разделение комментария и программы
***********************************************************
void the_function( void )
{
// далее настоящая функция.
code_goes_here(); }
/*********************************************************/
Во-первых, заметили ли вы, что я забыл поместить / в конце второй строки звездочек? Таким путем можно запросто терять целые функции. Во-вторых, трудно заметить, где оканчивается комментарий и начинается текст программы. Исправьте обе ошибки следующим образом:
/**********************************************************
* void the_function( void )
*
* Это многострочный комментарий, выполняющий все, что должен
* делать комментарий.
*
* Вертикальный столбец из звездочек слева облегчает
* зрительное разделение комментария и программы
* *********************************************************** */
void the_function( void )
{
// далее настоящая функция.
code_goes_here();
}
30. Используйте аккуратные столбцы везде, где можно.
Так как форматирование по сути является видом комментирования, то это правило применяйте также и к тексту программы. Два следующих блока функционально одинаковы, но заметьте, насколько легче искать имена переменных во втором блоке, причем не из-за выравнивания комментариев, а потому что имена образовали аккуратный столбец:
int x; // Опишите, что делает x.
unsigned long int (*pfi)(); // Опишите, что делает pfi.
const char *the_variable; // Опишите, что делает the_variable.
int z; // Опишите, что делает z.
x = 10; // Здесь идет комментарий.
the_variable = x; // Здесь второй комментарий.
z = x; // A здесь третий.
по сравнению с:
| int | x; | // Опишите, что делает x. |
| unsigned long int | (*pfi)(); | // Опишите, что делает pfi. |
| int | z; | // Опишите, что делает z. |
| const char | *the_variable; | // Опишите, что делает the_variable. |
| x | = 10; | // Здесь идет комментарий. |
| the_variable | = x; | // Здесь второй комментарий. |
| z | = x; | // A здесь третий. |
Вы можете рассматривать на этот вид форматирования как по сути "табличный", как если бы я создал таблицу со столбцами "тип", "имя" и "описание".
Другим хорошим местом для использования столбцов является список инициализации элементов в С++, который я форматирую следующим образом:
class derived : public base
{
string str;
const int x;
public:
derived( char *init_str, int init_x ) {}
}
derived::derived( char *init_str, int init_x )
:base( str, x )
,str ( init_str )
,x ( init_x )
{}
31. Не располагайте комментариев между именем функции и открывающей скобкой.
Основная сложность в следующем примере:
foo( int x )
/* Не помещайте
* комментарий
*/ здесь.
{
//...
}
заключается в том, что тело функции может оканчиваться на следующей странице или не помещаться на одном экране. То есть читающий не может сказать, видит ли он прототип или действительное определение. Поместите этот комментарий или до имени функции, или вставьте его в тело функции ниже открывающей скобки:
/* Или помещайте
** его здесь.
*/
foo( int x )
{
/* или здесь,
** с таким же отступом, что и программа.
*/
}
32. Помечайте конец длинного составного оператора чем-нибудь, имеющим смысл.
Прежде всего, подобные комментарии в конце блока:
while ( a < b )
{
for ( i = 10; --1 >= 0; )
{
f( i );
} // for
} // while
не дают ничего, кроме неразберихи, если блоки короткие. Я использую их только тогда, когда составной оператор слишком велик, чтобы поместиться на экран (в моем текстовом редакторе около 40 строк) или в нем столько уровней вложений, что я не могу понять суть происходящего. Комментарии в конце блока обычно целесообразны в больших составных операторах, но мне приходилось часто видеть подобный код:
На первой странице:
while ( a < b )
{
while ( something_else() )
{
for ( i = 10; --1 >= 0; )
{
for ( j = 10; --j >= 0; )
{
// далее идет масса кода
На какой-то из последующих страниц:
} // for
} // for
} // while
} // while
Эти комментарии слишком кратки, чтобы быть полезными. Завершающие блок комментарии должны полностью описывать управляющий оператор. Завершающие блок комментарии из предыдущего примера должны выглядеть таким образом:
} // for ( j = 10; --j >= 0; )
} // for ( i = 10; --1 >= 0; )
} // while ( something_else() )
} // while ( a < b )
Так как #ifdef почти всегда расположен на некотором расстоянии от #endif, то я всегда ставлю метку у #endif:
#ifndef __SOMEFILE_H_
#define __SOMEFILE_H_
// здесь следует 1000 строк программы
#endif // __SOMEFILE_H_
То же самое я делаю с #else.
33. Располагайте в строке только один оператор.
Нет абсолютно никакой причины упаковывать в одну строку столько операторов, сколько сможете, если у вас нет намерения сделать программу нечитаемой. Если в строке больше одной точки с запятой, то что-то неверно. Не используйте запятую-оператор (даже если вы знаете, что это такое) по той же причине. Очевидным исключением является оператор for, все три части которого должны быть на одной строке.
34. Указывайте имена аргументов в прототипах функций.
Это особенно важно в определениях классов. Страницы руководств (и встроенных систем помощи) для программы, над которой вы старательно работаете, вряд ли существуют в тот момент, когда они вам нужны больше всего - когда вы начинаете разработку. Вы обычно получаете документацию из двух мест: комментариев, добавленных к настоящим функциям и заголовочных файлов. Из них обычно лучше заголовочный файл, как более компактный. В любом случае из документации, которая на самом деле нужна по функции, вам необходимо знать порядок и число аргументов, а легче всего найти эту информацию в прототипе функции. Если ваш прототип похож на этот:
some_function( int, int, int, int, int );
то вам не удастся получить много помощи.
35. Используйте "предикатную" форму при разбиении длинных выражений.
"Предикатом" в английском языке называется вторая половина предложения - глагол и дополнение, над которым глагол выполняет действие. Порядок слов в английском предложении, конечно, фиксированный: глагол всегда идет первым.
Многие компьютерные языки имитируют структуру английского языка (языки С и С++ попадают в эту категорию). Паскаль, например, даже повторяет пунктуацию английского предложения: с точкой с запятой, отделяющей независимые операторы, и точкой на конце. Вызов функции является хорошим примером предикатной формы: глагол является именем функции, а прямые дополнения (вещи, на которые действует глагол) являются аргументами.
Вы также можете посмотреть на операторы типа глагола, потому что они выполняют некоторое действие над операндами ("объектами"). Это разумно, поэтому используйте ту же самую схему, что и в английском предложении, если вам нужно разбить длинное выражение на несколько строк. Помещайте сначала глагол (оператор):
if ( its_thursday_and_the_moon_is_in_scorpio()
|| its_friday_afternoon_and_close_to_quitting_time()
|| i_just_cant_bear_to_look_at_this_computer_for_another_minute()
)
{
go_home();
}
Конечно, вы можете добиться большего, просто сократив имена подпрограмм до чего-то более приемлемого, так чтобы все они поместились на одной строке.
Заметьте, как я расположил круглые и фигурные скобки в предыдущем примере с целью придания его структуре большей ясности. И при этом я использовал фигурные скобки, хотя язык этого не требовал, для облегчения поиска оператора, связанного с if. Следующий текст программы читается с большим трудом, потому что хуже видно, где заканчивается if и начинается оператор:
if ( its_thursday_and_the_moon_is_in_scorpio()
|| its_friday_afternoon_and_close_to_quitting_time()
|| i_just_cant_bear_to_look_at_this_computer_for_another_minute() )
go_home();
36. Подпрограмма должна помещаться на экране.
Затраты на вызов подпрограмм в С/С++ невелики; если для функции указано ключевое слово inline, то затрат фактически нет. Поэтому хорошая мысль состоит в том, чтобы создавать подпрограммы удобного в обращении размера и использовать их в больших количествах. Имя подпрограммы позволяет добиваться значительной абстракции. Если имена выбраны правильно, то у вас зачастую можете исчезнуть нужда в комментариях.
Вообще, мне нравится, когда рабочая часть подпрограммы (ее текст, в меньшей степени комментарии заголовка и так далее) видна полностью при редактировании; она должна целиком помещаться на экране или в окне.
37. Нужно обеспечивать возможность распечатки всего текста программы.
Часто проще найти ошибку на распечатанной странице, чем на экране, даже на большом. Текст на бумаге легче читается вследствие более высокого разрешения и лучшего фокусного расстояния, чем на экране. При этом вы можете разложить бумажные распечатки по всей поверхности стола. Вы вряд ли чем-нибудь сможете заменить бумагу в этом плане, если только у вас нет монитора с диагональю полтора метра и разрешением 300 точек на дюйм.
Итак, ваша программа должна легко печататься. Подпрограммы должны помещаться по возможности на одной странице (не более 60 строк), и ни одна строка программы не должна быть такой длины, чтобы не поместиться в строку распечатки (около 79 символов, в зависимости от шрифта), даже если ваш текстовый редактор поддерживает скролинг по горизонтали. Если вы выйдете за эти пределы, то будете вынуждены использовать столь мелкий шрифт для вывода, что совсем не сможете прочитать свою распечатку.
38. Используйте штриховую линию для зрительного разделения подпрограмм.
Я всегда ставлю такой комментарий:
//---------------------------------------------------------
над каждым определением функции. (И к тому же, я не использую штриховую линию нигде более). Хотя пустые строки замечательно подходят для зрительного разделения блоков программы, исключительно их использование не дает эффекта. Штриховая линия между функциями облегчает их поиск. Так же как пустая строка указывает на границу абзаца, штриховые линии подобны заголовкам разделов. Если мне нужно еще более четкое разделение, то я использую:
//==========================================================
//ОПИСЫВАЮЩИЙТЕКСТ //==========================================================
Подумайте об этом, как о заголовке для главы. Я стараюсь не помещать никаких комментариев, за исключением
штриховых линий, вне функции, потому что такие комментарии затрудняют обнаружение определений этой функции. При этом я форматирую функции следующим образом:
//---------------------------------------------------------















