- О стиле программирования
- Работа
О стиле программирования
Эта глава является заключительной в кратком описании языка Си и посвящается важной части в работе программиста, которой зачастую пренебрегают. Речь пойдет о стиле программирования или, точнее, о стиле оформления программ.
Большинство программистов-одиночек разрабатывают программы в твердой уверенности, что делают это ««для себя», что никто никогда не заинтересуется в содержимом исходных текстов их программ, и потому нет смысла тратить время и силы на всякие ««излишества» и ««украшения». Это в корне неверное предположение! Известен афоризм ««всякая хорошо работающая вещь - красива», который вполне применим и к программе.
Ранее было показано, что язык Си допускает много разных способов (1) в составлении выражений, в записи операторов и т.д. Очень часто такое изобилие ««инструментария» воспринимается программистом как стимул писать витиеватые программы, изобилующие огромным количеством макросов, переопределяющих едва ли не все ключевые слова языка, многократно и часто без необходимости вложенными друг в друга операторами и т.п. Все это выдается за высокий класс программиста, но фактически является лишь одним из проявлений каких-то комплексов, ничего общего с квалификацией не имеющих.
Качественная программа должна легко читаться, для чего порой комментариев в ней оказывается больше, чем собственно операторов. Кроме комментариев, существует и еще способ улучшить читаемость программного текста. Речь идет о так называемом ««самодокументировании» программы. Одно время популярной была так называемая венгерская нотация, при которой любой идентификатор содержит в своем начале особым образом закодированный тип (например, все строки начинаются с символа s, указатели с ptr, целые числа- с i и т.п.), однако принципиальным можно считать лишь осмысленность любого идентификатора.
Если программа обрабатывает строки, являющиеся именами и фамилиями людей, то более удачным следует признать такие определения;
#define MAX_PERSONAL_COUNT 100
typedef struct{
char name[];
char gender[];
char age;
} people_struct;
people_struct personal_list[MAX_PERSONAL_COUNT];
чем более короткий, но эквивалентный по смыслу вариант
struct )
char al[];
char a2[];
int a3;
} arr[100];
Для человека, хоть немного владеющего английским, первый вариант расскажет сам за себя: первая строка определяет максимальное количество персон, далее следует определение нового типа-структуры с полями Имя, Пол и Возраст, далее объявляется массив списка персонала. Вторая же запись понятна лишь в программистском смысле, т.е. уловить связь массивов и полей структуры с реально осуществляемыми действиями невозможно. Спустя определенный срок программист, написавший программу в первом стиле (и потративший на это немного больше времени), вспомнит все тонкости своей программы за 5 минут, в то время как второй (состряпавший свой вариант на пару часов быстрее) наверняка потратит не один день на это (2)…
Для качественного оформления текста программы обязательно следует использовать выделение иерархически связанных участков при помощи отступов – это значительно улучшает восприятие заложенного в программу алгоритма. Фигурные скобки, ограничивающие тело функций и операторов, принято размешать одним из следующих способов:
for (;;)
{
// уровень операторов цикла
}
и
for (;;){
// уровень операторов цикла
}
То есть в первом способе открывающая и закрывающая скобки оператора находятся на одном уровнем с самим оператором, но на разных строках, а тело сдвинуто вправо. Во втором случае открывающая скобка находится рядом с оператором, а закрывающая – на уровне оператора. Оба способа позволяют, проследив вертикальные уровни скобок, легко разобраться в уровне вложенности операторов:
for(;;)
{
while (x)
{
if (x)
{
a = x *2;
}
else
{
a = x + 2;
}
}
}
и
for(;;){
while (x){
if (x){
a = x *2;
}else{
a = x + 2;
}
}
}
Желательно, выбрав один раз приемлемый для себя стиль оформления программ, придерживаться его все время. Постепенно это станет привычкой и не будет восприниматься рутинной обязанностью.
Очень желательно оформлять в виде функций повторяющиеся в разных местах программы участки. Как правило, если участок повторяется 2 или более раз – его стоит оформить в виде функции. Иногда очень удобно оформлять функции не по количеству повторов, а по смыслу выполняемых действий. Например, часто бывает удобно «набросать костяк» алгоритма, обозначив его характерные этапы функциями, которые затем реализовать:
int main(void){
init_all(); // инициализация всей периферии
while(1){ // главный цикл
display(); // обновление дисплея
if(test_key() ){ // проверка нажатия клавиатуры
// если кнопка нажата - проанализировать и обработать
switch (get_key()){
case 0 : press_key0(); break
case 1: press_key1(); break;
}
}
}
}
В этом простом примере показана «заготовка» едва ли не любой программы для микроконтроллера, взаимодействующей с пользователем при помощи кнопок и дисплея. Составив такой скелет, программист может сосредоточиться на реализации уже придуманных функций get_key() – получение кода нажатой кнопки, display() – обновления содержимого дисплея и т.д.
Такой порядок разработки программы можно назвать «от общего к частностям» (иногда используют термин нисходящее программирование). Соответственно, при реализации функций так же можно применить этот способ. Заботиться о количестве функций и о том, что многие из них используются лишь один раз, не стоит – оптимизатор все сделает лучшим образом. Программист должен думать, а процессор – работать.
- В этой книге изложены далеко не все особенности синтаксиса языка Си – с целью упрощения. Показан лишь необходимый минимум для начала освоения.
- Видимо, на этом основана поговорка программистов «легче сделать все с начала, чем разобраться в ранее написанном»