Справочник функций

Ваш аккаунт

Войти через: 
Забыли пароль?
Регистрация
Информацию о новых материалах можно получать и без регистрации:
реклама
на softobase.com/ru тебя ждет твоя программа для нарезки музыки для windows

Почтовая рассылка

Подписчиков: -1
Последний выпуск: 19.06.2015

Советы по написанию хороших программ..

Содержание:

  1. Критерии хорошести программ
  2. Общие соображения
  3. Методы оптимизации программ
  4. Методы увеличения "читаемости" программ
  5. Методы нахождения и исправления ошибок
  6. Часто встречаемые ошибки
  7. Ассемблерный код
  8. Создание объектных моделей
  9. Проектирование баз данных
  10. Организация работы

Примечание: Данные правила собирались в течение достаточно долгого времени, и к настоящему моменту часть их может оказаться устаревшей или слишком специфической, а может быть и просто банальной.

Критерии хорошести программ

Общие соображения

Методы оптимизации программ

  • Перейдите на более оптимизирующий компилятор (тот же Watcom).
  • Обычно при оптимизации надо найти маленький кусочек, который жрет 90% ресурсов, и уж его заоптимизировать до смерти (см. закон 80% - 20%).
  • Меньше мспользовать динамическое выделение памяти. Стандартные менеджеры памяти обычно медленны. В некоторых случаях даже имеет смысл написать свой менеджер.
  • Полезно пройтись по программе Turbo Profiler'ом, найти критические места и соптимизировать их или переписать на ассемблер.
  • Все сложные вычисления выносить из цикла и проводить один раз.
    Например, вместо for(i=0;i<100;i++) a[i]=i*320+500;
    лучше написать: for(i=0,j=500;i<100;i++,j+=320) a[i] = j;
    а еще лучше: for(b=a,i=500;i<32500;i+=320) *b++ = i;
  • Если какую-то формулу, которую нужно вычислять часто, можно загнать в табличку - стоит так и сделать.
    Пример - синус и косинус.
  • Во многих компиляторах имеет смысл меньше использовать байтовые переменные, т.к. операции над ними все равно будут производиться в DWord-регистрах, и теряется время на преобразование байта в Word или DWord
  • if( a*d > c*b ) лучше (если нет проблем со знаком), чем if( a/b > c/d ) - так не теряется точность и нет деления на ноль.
  • Inc( a, b ) или a += b работает быстрее, чем a = a+b;
  • Стоит передавать функции меньше параметров - тогда Watcom сможет их всех передать через регистры.
  • Поскольку деление осуществляется медленнее умножения, то для деления на небольшие числа можно завести табличку чисел 1/X, и вместо деления умножать на 1/X из таблицы.
  • Меньше использовать действительные числа, а больше целые. Кстати, в паскале очень тормозит тип Real, т.к. он нестандартен для сопроцессора. Хотя на пентиуме тип float уже не медленнее.
  • При работе с графикой меньше использовать видеопамять - она медленная (хотя есть и акселерированные видеокарточки, но все равно все идет по шине). Если каждый раз перерисовывается немного, то можно кидать в видеопамять только "разницу" между экранами (особенно для Trident 9000 и других медленных карт).
  • Меньше работать с XMS. (Это требует переключения в защищенный режим). При работе с блоками 640 байт она медленнее обычной в 2.5 раза, при блоках 40 байт - в 7 раз.

Методы увеличения "читаемости" программ

Методы нахождения и исправления ошибок

  • Программу писать постепенно: написать одну функцию, отладить, убедиться что все работает, потом еще чуть-чуть, а не писать сразу сотню строк и искать в ней ошибки.
  • Двигаться постепенно от варианта, когда программа работает к варианту, когда она не работает, и смотреть, что изменяется.
  • Правило: чем яснее алгоритм, тем труднее в нем ошибиться.
  • Включить все предупреждения и посмотреть программу. Так легко вылавливаются ошибки типа if(a=b) вместо if(a==b).
  • По всей программе пишутся printf() и смотрится на каком шаге глюки
    Замечание: Главное - не ошибиться в самом printf(), а то будет еще хуже.
  • Посмотреть соответствие скобок (это есть во многих редакторах). Если компилятор ругается совсем непонятно на что, то возможно где-то выше не закрыта скобка.
  • Использовать инварианты - условия, которые должны всегда выполняться. В отладочной версии можно понавставлять вызовов функции проверки инвариантов, который будет вываливать ошибку при нарушении инварианта.
  • Писать тесты! Лучше потратить время на написание теста для каждого маленького кусочка, чем потом мучаться искать ошибки в большом проекте.
  • Посмотрите следующий раздел - может быть ваша ошибка там уже описана.

Часто встречаемые ошибки

  • int a[10]; for(i=0;i<=10;i++) a[i]; или другие варианты выхода за пределы
  • if(a=b)
  • Не работать с нулевыми указателями!!!
  • unsigned a,b; if( a-b < 0 ) ;
  • f(x)/*W; - то ли делить на ссылку, то ли комментарий
  • Watcom: при использовании intr / in386x обнулять сегментные регистры
  • Может глючить вариант /*/
  • Создаешь указатель, не выделяешь память и потом туда пишешь. Эффект потрясающий! Или, более общий случай - неинициализированная переменная (Java такие вещи отслеживает).
  • Borland C плохо работает с указателями типа huge
  • Watcom: При чтении fscanf("%d",&i) из файла без проверки на feof и без пустой строки в конце, последнее значение считывается дважды. Лечится: fscanf("%d\n",&i)
  • Перед делением стоит проверить а не на ноль ли мы делим.
  • После целочисленного умножения (и сложения) значение не всегда влазит в переменную или регистр.
  • Не надо забывать abs и fabs, и не надо их путать.
  • Помнить про преобразование типов.
    Если val преобразовать к int, то при сравнении if( val > eps ) всегда маленькое val будет нулем :-(
  • Если в языке нет автоматического преобразование к типу, то надо внимательно следить за типами.
  • Пишешь в неоткрытый файл или читаешь из оного.
  • Использование данных больше 64K в 16-битной программе.
  • int i; scanf( "%d", i );
  • const a = 0.001; (по умолчанию тип int)
  • for( unsigned i=100; i>=0; i-- );
  • Многие новые компиляторы стали по умолчанию выравнивать структуры данных на границу двойных слов, поэтому при описании внешних структур данных, например формата заголовков графических файлов, структуры VESA, и т.д. надо отменить это выравнивание при помощи #pragma pack( 1 )
  • Ассемблер: Перед делением регистра на регистр забываешь обнулить edx.

Ассемблерный код

  • Избегать медленных команд - IDiv, Div, IMul, Mul, Jmp, Jcc
  • В 32-битной модели стараться не использовать 16-битных регистров
  • Стоит писать код так, чтобы Pentium мог выполнять команды парами
  • Будьте проще! (и за вами потянутся массы):
    Избегайте сложных команд типа Movzx, Loop, LodSD, ...
    Dec ecx; Jnz ... работает быстрее, чем Loop ...
  • Neg edx:eax = Neg edx; Neg eax; Sbb edx,0
  • Проверка четырех условий с укладкой командой SETcc reg8; SHL reg32,8; и CMP reg32,1010101h; JZ метка; работает ощутимо быстрее, чем 4 Jcc
    или: Cmp ;(SetB) Rcl eax,8; или Shl eax,8 -> Ror eax,1
  • bx = ax + bx*320 для 8086 (320 = 1.0100.0000b):
    Xchg bh,bl; Add ax,bx; Shr bx,1; Shr bx,1; Add bx,ax
    286: Add ah,bl; Shl bx,6; Add bx,ax
  • Умножение eax на 5: Lea eax,[eax+eax*4]
  • Деление eax на 3: Mov edx,0x55555555; IMul edx;
  • Shl eax,imm8 сильно быстрее Shl eax,cl. Лучше модифицировать код.

Создание объектных моделей

Проектирование баз данных

  • Если в процессе работы делается выборка по нескольким полям, то стоит делать групповые индексы, а не несколько индексов.

Организация работы

  • В процессе работы необходимо осозновать, что главной целью является создание программного продукта, а все остальное - второстепенно. Т.е. установкой и "опробованием" новых средств, методов, и т.д. заниматься стоит, но главным является сдать проект в срок.
  • Работу стоит разделять на "итерации" длительностью порядка одной недели. И раз в неделю собираться всей командой разработчиков, обсуждать результаты и проблемы, решать продолжать работу и определять цели следующей итерации.

Оставить комментарий

Комментарий:
можно использовать BB-коды
Максимальная длина комментария - 4000 символов.
 
Реклама на сайте | Обмен ссылками | Ссылки | Экспорт (RSS) | Контакты
Добавить статью | Добавить исходник | Добавить хостинг-провайдера | Добавить сайт в каталог