ВУЗ: Не указан
Категория: Не указан
Дисциплина: Не указана
Добавлен: 23.12.2021
Просмотров: 209
Скачиваний: 3
Технологія створення програм
Кодування і документування програм
З надбанням досвіду програміст виробляє власні правила і стиль. При цьому корисно вчитися не тільки на власних невдачах а й на помилках інших. Розумне дотримування наведених нижче рекомендацій допоможе уникнути багатьох розповсюджених помилок.
Звичайно, на всі випадки життя дати рекомендації неможливо, але недарма програмування, особливо на початку його розвитку, вважалось мистецтвом
Головна мета до якої треба прагнути - отримати програму зручну для читання, можливо більш простої структури. Широко відомий вірний в більшості випадків девіз - "Better simpler then Clever" (Краще простіше ніж по розумному)
В кінцевому випадку всі технології програмування направлені на досягнення саме цієї мети, оскільки тільки так можна досягти надійності та простоти модифікації програми. Зміст девізу полягає в тому, що якщо будь-яку дію можна запрограмувати різними способами, але перевага повинна надаватися не найбільш компактному і навіть не найбільш ефективному, а такому, який легший для програмування.
Перший крок в написанні програми - це написання на природній мові (можливо з застосуванням узагальнених блок-схем), що конкретно і як саме вона повинна робити.
Таке описання алгоритму корисне по декільком причинам: воно допомагає в деталях продумати алгоритм, знайти на самій ранній стадії помилки, розбити програму на логічну послідовність блоків, а також забезпечити коментарі до програми.
Якщо алгоритми можна розбити на послідовність завершених дій (а до цього потрібно прагнути!), кожна закінчена дія оформляється у вигляді функції.
Кожна функція повинна вирішувати тільки одне завдання (не потрібно об’єднувати два коротких незалежних фрагмента в одну функцію).
Розмір функції може змінюватися в великих межах, все залежить від того який розмір має закінчений фрагмент коду, який виділяється в функцію. Бажано щоб функції поміщались на 1-му, 2-х екранах: однаково складно розібратись в програмі яка містить декілька величезних функцій, і в розсипу із сотні підпрограм по декілька стрічок кожна.
Якщо деякі дії зустрічаються в тілі програми хоча б 2 рази, їх також слід оформити у вигляді функції. Однотипні дії оформляються у вигляді перезавантажених функцій або функцій з параметрами. Короткі функції є зміст оголошувати з директивою inline.
Необхідно ретельно вибирати імена змінних. Не захоплюйтесь скороченнями, вони зменшують читабельність програми, і часто можна забути як саме було скорочено те чи інше слово. Загальна тенденція полягає "в тому, що чим більша область видимості змінної, тим довше у неї ім’я".
Перед таким іменем часто ставиться префікс типу (одна або декілька букв, по яким можна визначити тип змінної). Для лічильників коротких циклів, навпаки, краще обійтись однобуквеними іменами типу i, j, k.
Імена макросів бажано записувати великими літерами щоб відрізняти їх від других об’єктів програм.
Не рекомендується використовувати імена які починаються з символу підкреслювання, імена типів які закінчуються на _t, а також ідентифікатори які співпадають з іменами ресурсів стандартної бібліотеки С++.
Змінні бажано ініціалізувати при їх об’явленні, а об’являти як можна ближче до місця їх використання. з іншого боку зручно всі об’явлення локальних змінних функцій розташовувати на початку блоку, так щоб їх було просто знайти. При невеликих розмірах функцій обидва ці побажання достатньо легко сумістити.
Локальні змінні мають перевагу над глобальними. Якщо глобальна змінна все ще потрібна, краще об’явити її статичною, що обмежить область її дії одним вихідним файлом.
Всю необхідну для функції інформацію потрібно намагатися передавати в якості параметрів, а не через глобальні змінні, зміну яких важко відслідковувати.
Вхідні параметри функції, які не повинні в ній змінюватися, слід передавати як константні посилання, а не по значенню. Крім покращення читабельності програми і зменшення можливості випадкових помилок, цей спосіб більш ефективний, особливо у випадку передачі складних об’єктів.
Виняток складають параметри розміри яких менше розміру покажчика - їх ефективніше передавати по значенню (не забувайте вказати const).
Вихідні параметри функції краще передавати по адресі, а не по посиланню, щоб з семантики виклику функції можливо було зрозуміти, що всередині неї параметр змінюється.
Не можна повертати з функції посилання на локальну змінну, тому що вона автоматично знищується при виході із функції яка є областю її дії.
Слід уникати використання в програмі чисел в уявному виді. Константи повинні мати осмислені імена, задані через const або enum (останнє має перевагу, так як пам’ять під перерахування не виділяється). Символічне ім’я робить програму більш зрозумілою, а крім того при необхідності змінити значення константи це можна зробити всього лиш в одному місці програми.
Для запису кожного фрагменту алгоритму потрібно використовувати найбільш підходящі засоби мови. В принципі будь-який цикл можна реалізувати за допомогою операторів goto та if, але це було б нераціонально, оскільки за допомогою операторів циклу ті ж дії легше читаються, а компілятор генерує більш ефективний код. Краще надавати перевагу розгалуженням на декілька напрямів за допомогою оператора switch, а не декількох if. Гарний спосіб передачі управління одної функції з групи - масиву покажчиків на функції.
Слід уникати зайвих перевірок умов. Наприклад замість операторів
if (strstr(a, b)>0) {...}
else if (strstr(a, b)<0) {...}
else if(strstr(a, b)==0) {...}
краще написати
int is_equal = strstr(a, b);
if (is_equal > 0) {...}
else if (is_equal <0 ) {...}
else {...} // тут is_equal==0
Якщо перша гілка оператора if включає передачу управління використовувати else немає необхідності:
if(is_equal > 0){...break;}
if(is_equal < 0){...return;}
{...} // тут is_equal==0
Безглуздо використовувати перевірку на рівність нулю (або, що ще гірше на рівність true або false):
bool is_busy;
...
if (is_busy == true){...} // погано! краще if (is_busy)
if (is_busy == false){...}// погано! краще if (!is_busy)
char s[80];
while (fgets(s)!=NULL){...}// погано !краще while (fgets(s))
while (a==0){…} // можна while(!a)
Якщо одна з гілок умовного оператора набагато коротша, ніж інша, більш коротшу гілку if краще помістити зверху, інакше вся управляюча структура може не поміститись на екрані, що затягне відлагодження.
В деяких випадках умовна операція краще умовного оператора:
іf (z) i=j; else i=k; // краще так : i=z ? j : k;
При використанні циклів потрібно намагатися об’єднувати ініціалізацію, перевірку умови виходу і прирощення в одному місці.
Часто зустрічаються помилки при програмуванні циклів - використання в тілі циклів не ініціалізованих змінних та невірний запис умови виходу з циклу.
Щоб уникнути помилок рекомендується
-
Перевірити чи всім змінним що зустрічаються в правій частині операторів присвоювання в тілі циклу присвоєні до цього номінальні значення;
-
Перевірити чи змінюється в тілі циклу хоча б одна змінна яка входить в умову виходу з циклу;
-
Передбачити аварійний вихід з циклу по досягненню деякої кількості ітерацій;
-
І звичайно не забувати про те що якщо в тілі циклу необхідно виконати більше одного оператора потрібно заключати їх в фігурні дужки.
Оператори циклу взаємозамінні, але можна привести деякі рекомендації по вибору найкращого в кожному конкретному випадку.
Оператор do…while використовують коли цикл потрібно обов’язково виконати хоча б один раз (наприклад, якщо в циклі проводиться введення даних).
Оператор for має перевагу в більшості інших випадків (однозначну для організації циклів з лічильниками).
Оператор while краще використовувати в випадках коли число ітерацій заздалегідь невідоме, очевидних параметрів циклу немає або модифікацію параметрів зручніше використовувати в кінці тіла циклу.
Необхідно перевіряти коди повернення помилок і передбачувати роздрукування повідомлень в точках програми, куди управління при нормальній роботі програми передаватися не повинно. Наприклад, оператор switch повинен мати слово default з обробкою ситуації по замовчуванню, особливо якщо в ньому перераховані всі можливі значення перемикача.
Коментарі мають дуже важливе значення, тому що програміст частіше читає ніж пише. Програми на C++ досить непогано читабельні (краще ніж програми на PERL, але гірше ніж на PASCAL) і в них особливо важко притримуватися гарного стилю при форматуванні та документації.
Коментарі повинні представляти собою правильні речення без скорочень і з знаками правопису і не повинні підтверджувати очевидне (тип виклику функції або описання змінних).
Якщо коментарій до фрагменту програми займає декілька стрічок, його краще розмістити до фрагменту, чим справа від нього і вирівняти по вертикалі. Абзацний відступ коментаря повинен відповідати відступу коментуємого блоку.
//коментар, який описує
//що відбувається в нижньому
//блоці програми
{/* Незрозумілий блок програми*/}
Для розділення функцій та інших закінчених фрагментів користуйтесь пустими стрічками або коментарями виду
//-----------------------------------------------------------------------------------------
Вкладені блоки повинні мати відступ в 3-4 символа, причому блоки одного рівня вкладеності повинні бути вирівняні по вертикалі. Бажано, щоб закриваюча фігурна дужка знаходилась строго під відкриваючою.
Форматуйте текст стовпцями всюди, де це можливо:
#include <string.h>
#include <stdlib.h>
int main (){
double m[10]; // коментар
const char s[]=”2,38,5.70.0.0.1”; // коментар
char *p=s; // коментар
int i=0; // коментар
//-----------------------------------------------------------
do {
m[i++]=atof(p);
if (i>9)break;
}
while (p=strstr(p,’,’), p++);
for(int k=0;k<i;k++)
printf (“%5.2f”,m[k]);
return 0;
}