|
Супер-модератор
|
||||||||||||||||||||||||||||||||||||||||||||||
Как не надо писать программы22.09.2014, 21:10. Показов 22385. Ответов 4
Метки нет (Все метки)
При написании графических программ большинство проблем проявляется более остро, поэтому я хочу рассказать о том, чего не надо делать, когда пишется программа с графическим интерфейсом, и приведу основные способы исправления часто встречающихся ошибок. Все фрагменты кода, которые я здесь рассматриваю, взяты мной из вопросов на разных форумах по программированию, я ничего не придумал (иногда в вопросах новичков встречается такое, что мне бы фантазии не хватило придумать это)
Итак: Когда вы пишете графическую программу, вы не должны ... ... рассчитывать на то, что размер экрана постоянен, и равен 640 пикселей по горизонтали на 480 по вертикали. Простейший код - заставка: приветствие пользователя. В центре экрана должна появиться надпись 'Hello'. Что делают новички?
Написав код правильно:
... использовать "магические числа", полагаясь на то, что вы всегда будете использовать для вывода текста один и тот же шрифт, и работать в одном и том же разрешении. Этот пункт является по сути продолжением предыдущего пункта. Итак, была поставлена задача вывести несколько строк, и обвести их прямоугольником (что-то подобное всплывающему меню в Windows-приложениях). Вот так эта задача была решена:
после чего программист, считая, что здесь прокола не будет, использует эту процедуру в своей программе "по полной". И в какой-то момент сталкивается с проблемой: Шрифт был изменен с дефолтного на SmallFont, отображение уже не такое, как прежде, и придется искать неправильную константу и исправлять ее (скорее всего - методом подбора). А этого опять же можно было избежать, сразу ориентируясь на работу с разными шрифтами:
(smallfont, 4) (gothicfont, 5) ... использовать числовые значения вместо именованных констант. В общем-то, этого правила стоило бы придерживаться не только при программировании графики, но и вообще при любом программировании, особенно начинающему программисту. Однако, как показывают вопросы, задаваемые на форумах, этого правила новички как раз и не придерживаются. А зря. Мне, например, гораздо сложнее понять, что такое:
Ну, и еще одно замечание. Не перемешивайте логику и интерфейс. Я уже устал говорить об этом, но, похоже, меня не слышат. Если вы делаете графическое меню, то функция отображения должна только отображать его, ни в коем случае не выполняя действия, "подключенные" к этому пункту меню. Потому, что если вам потом захочется сделать другое меню (или текстовое, или тоже графическое, но, скажем, трехмерное), то при разделенных логике/интерфейсе достаточно будет написать новую функцию, отображающую менюшки, а все остальное останется без изменения. В большинстве же проектов, которые пишут студенты начальных курсов ВУЗов, проще переписать всю программу заново, чем чуть-чуть изменить ее внешний вид (потому что все переплетено настолько вычурно, что только потяни за одну ниточку, все запутается окончательно).
12
|
||||||||||||||||||||||||||||||||||||||||||||||
| 22.09.2014, 21:10 | |
|
Ответы с готовыми решениями:
4
Как писать программы? Подскажите, пожалуйста, как писать данные программы, чтобы я понял принцип Как писать программы с неравенствами? |
|
Супер-модератор
|
||||||||||||||||||||||||||||||||||||
| 22.09.2014, 21:16 [ТС] | ||||||||||||||||||||||||||||||||||||
|
(продолжаем...)
Турбо Паскаль и нехватка памяти / ошибки №48, №49 В связи с возросшим количеством вопросов на темы "Программе не хватает памяти, что делать", "Ошибка компиляции №48 (или №49), помогите", "Программа вылетает с переполнением стека, куда копать?", хотелось бы привести основные моменты, на которые стоит обратить внимание при написании программ. Особенно рекомендуется к прочтению новичкам в написании сложных, развернутых проектов, в частности таких, которые собираются из нескольких уже работающих по отдельности фрагментов. (все написанное ниже относится только к программированию в Турбо Паскале, многое из этого в более современных компиляторах уже неактуально, хотя кое что может и пригодиться) Ошибка №48 - Code segment too large (сегмент кода слишком большой). Возникает в случае, когда размер кода, получаемого при компиляции программы, превышает 65520 байт (то есть, размер одного сегмента). С этой ошибкой бороться относительно легко, и путей борьбы здесь несколько.
Как пример (из реальной программы, по которой был задан подобный вопрос):
Отвлечемся ненадолго от ошибки №48, и посмотрим ... Ошибка №49: Data segment too large (слишком большой сегмент данных) Это происходит в случае, когда общий размер данных (глобальных данных, нужно заметить, потому что локальные размещаются не в сегменте данных) всех модулей превышает отведённый для них размер в 65520 байт. Простым разбиением на модули эту ошибку побороть нельзя: дело в том, что программа на Паскале может содержать несколько сегментов кода, и только один (общий для всех модулей) сегмент данных. Так что, если каждый из ваших модулей по отдельности компилируется - это ещё ничего не значит, при линковке exe-файла все ещё может "всплыть" сообщение об ошибке №49. Например: Первый модуль:
Но и с этой ошибкой можно бороться. И тоже не одним способом: Способ первый - проверяем, действительно ли нужны массивы типа LongInt. Как пример: нужно хранить в массиве рост 10000 школьников с точностью до сантиметра. И зачем тут longint? Достаточно типа byte (поправьте меня, если я ошибаюсь, но рост более 255 сантиметров для школьника - глупо), экономия четырехкратная. После изменения базового типа на byte даже только в одном из модулей мы избавляемся от "ошибки №49". Особое внимание обратите на строковые типы: по умолчанию для string-а резервируется 256 байт. Это не всегда нужно, можно существенно уменьшить размер данных ограничением длины строки через string[длина]. То же самое касается вещественных типов: вместо использования real (6 байт) используем single (4 байта). Во-первых, экономия памяти в случае использования массивов, во вторых - увеличение быстродействия программы (тип real вообще очень медленный, поскольку он является "чужеродным" для сопроцессора, и его конвертация в сопроцессорный тип занимает кучу времени). Способ второй - используем динамическое выделение памяти вместо статического, в результате данные хранятся не в сегменте данных, а в "куче", следовательно, опять избавляемся от ошибки №49: Модуль №1
5
|
||||||||||||||||||||||||||||||||||||
|
Супер-модератор
|
|||||||||||
| 22.09.2014, 21:19 [ТС] | |||||||||||
|
RunTime error 202: Stack overflow error (или "Программа вылетает с переполнением стека") Причиной этого является то, что в стеке закончилось место для размещения локальных переменных подпрограммы. То есть, если есть программа:
(Также эта ошибка очень часто возникает при разработке - неправильной, естественно - рекурсивных подпрограмм. Об этом - чуть ниже) И опять же есть несколько способов борьбы и с этой ошибкой:
Что касается рекурсии:
Ну, и еще несколько общих рекомендаций при разработке программ:
6
|
|||||||||||
|
Супер-модератор
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| 22.09.2014, 21:22 [ТС] | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
(заканчиваем)
Паскаль - это язык с очень мощной системой типов. Если правильно использовать этот факт, то можно ловить некоторые ошибки в программе еще на этапе компиляции. Например: (неправильное использование)
(правильное решение)
Повторяю: Паскаль - это язык с очень мощной системой типов. Пользуйтесь этим. Не экономьте на введении новых типов в свою программу. Простое описание типа не увеличивает размер exe-файла программы, какого бы большого размера не был описываемый тип. Т.е., не экономьте подобным образом (описанием типа [1 .. 1], я имею в виду):
Решается это очень просто:
Еще один пример, когда описание нового типа помогает справиться с задачей быстрее/проще, чем было без него. Всем хорошо известная задача: поменять в матрице вторую и четвертую строку. "Ну, чего тут сложного," - говорит новичок, и лихо пишет программу:
Ну, и еще кое-что. Я постоянно говорю об этом на форумах, но все время встречаю ошибки, связанные с нежеланием придерживаться этого простого совета: объявляйте переменную как можно ближе к тому месту, где она должна использоваться. Особенно это касается счетчиков цикла. Вот программа, иллюстрирующая ошибку:
Вот так надо было писать программку:
И еще одно уточнение, касающееся этой программы: заметили в 14-ой строке, что я не написал:
Повторяю еще раз: Паскаль - это язык с очень мощной системой типов, и это накладывает свои требования: даже две переменных (казалось бы одинакового типа)
8
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Супер-модератор
|
|||||||||||||||||||||||||||||||||||||||||||||||
| 22.09.2014, 21:24 [ТС] | |||||||||||||||||||||||||||||||||||||||||||||||
|
Решил дополнить список того, как делать не надо.
То, о чем будет сказано ниже - относится в основном к новому компилятору - FPC... Не используйте в качестве параметров функционального (процедурного) типа функции с неправильной сигнатурой. Объясню на примере. Вы все, конечно, слышали, что для передачи в подпрограмму своей функции, надо предварить ее имя операцией взятия адреса? Далеко ходить не буду, открываем один из примеров, идущих с FPC, называется winhello.pp, находится он в папке \FPC\{версия}\demo\win32, и создается в этом примере простейшее Win32 приложение. Вот одна из процедур этой программы:
Еще примеры? Пожалуйста, открываем DRKB, смотрим пример использования функции EnumWindows. Я его немного упростил, вот в таком виде программа компилируется FPC:
Кто-нибудь задумывался, почему, собственно, надо добавлять этот вездесущий "@"? Посмотрите в любой книге по Турбо-Паскалю тему "Процедурные типы". Вы там хоть один такой символ при передаче функции как параметра в другую функцию видели? Что же произошло, что теперь компиляторы требуют везде брать адрес, интересно? А ничего не произошло. Все дело - в том, что этот значок никому не нужен. Вы этим самым оказываете и себе и компилятору медвежью услугу - вместо того, чтобы описать Callback функцию правильно, вы берете адрес этой функции, который совместим с любым другим указателем. Вспомните, что
Что же надо сделать, чтобы исправить приведенные выше примеры? Очень немного. 1. Оконная функция. Смотрим в MSDN (если не помним наизусть) сигнатуру оконной функции:
2. Функция перечисления окон. Аналогично: смотрим описание EnumWindows, чтобы узнать, какая функция ожидается первым параметром. А вот такая:
То же самое касается и излюбленных хаков: запуска функций через RunDll32. Очень много в интернете советов подобного рода:
Интерфейс программ Windows Rundll и Rundll32 Вот что:
И после этого люди еще удивляются, что "обратная смена невозможна"? Удивляться-то надо не этому, а тому, что оно вообще хоть как-то работает. Опять же, отсюда и эти самые "работает только на Win98, или только на Win95". Запуск функции с подходящими сигнатурами поддерживается на всех версиях Windows. А вот поддерживать то, что изначально не предполагалось - извините, никто не обязан. P.S. Я говорю об этом каждый раз: Паскаль - очень мощный язык, но используйте его правильно, не пытайтесь "объегорить" ни компилятор ни ОС. Выйдет себе дороже. Я надеюсь, хоть кто-то задумается над тем, что я тут написал, и перестанет бездумно добавлять операторы в программу для того, чтобы ее откомпилировать с наименьшими затратами усилий... Лучше потерять чуть больше времени, но разобраться в причинах, по которым компилятор отказывается выполнять свою работу, и исправить именно сами причины, а не закрывать глаза на следствия. Желающие скачать этот топик отдельным PDF-файлом могут это сделать, в аттаче точная копия топика.
14
|
|||||||||||||||||||||||||||||||||||||||||||||||
| 22.09.2014, 21:24 | |
|
Помогаю со студенческими работами здесь
5
Литература: как писать программы в паскале Надо ли в конце программы до end писать readln Помогите писать на С++ через шаблоны. Консуле я писал, но надо писать исползуя шаблоны Как создать программу которая бы выводила рандомно примеры и надо было правильно писать ответы как писать программы Искать еще темы с ответами Или воспользуйтесь поиском по форуму: |
|
Новые блоги и статьи
|
||||
|
Новый ноутбук
volvo 07.12.2025
Всем привет.
По скидке в "черную пятницу" взял себе новый ноутбук Lenovo ThinkBook 16 G7 на Амазоне:
Ryzen 5 7533HS
64 Gb DDR5
1Tb NVMe
16" Full HD Display
Win11 Pro
|
Музыка, написанная Искусственным Интеллектом
volvo 04.12.2025
Всем привет. Некоторое время назад меня заинтересовало, что уже умеет ИИ в плане написания музыки для песен, и, собственно, исполнения этих самых песен. Стихов у нас много, уже вышли 4 книги, еще 3. . .
|
От async/await к виртуальным потокам в Python
IndentationError 23.11.2025
Армин Ронахер поставил под сомнение async/ await. Создатель Flask заявляет: цветные функции - провал, виртуальные потоки - решение. Не threading-динозавры, а новое поколение лёгких потоков. Откат?. . .
|
Поиск "дружественных имён" СОМ портов
Argus19 22.11.2025
Поиск "дружественных имён" СОМ портов
На странице:
https:/ / norseev. ru/ 2018/ 01/ 04/ comportlist_windows/
нашёл схожую тему. Там приведён код на С++, который показывает только имена СОМ портов, типа,. . .
|
Сколько Государство потратило денег на меня, обеспечивая инсулином.
Programma_Boinc 20.11.2025
Сколько Государство потратило денег на меня, обеспечивая инсулином.
Вот решила сделать интересный приблизительный подсчет, сколько государство потратило на меня денег на покупку инсулинов.
. . .
|
|
Ломающие изменения в C#.NStar Alpha
Etyuhibosecyu 20.11.2025
Уже можно не только тестировать, но и пользоваться C#. NStar - писать оконные приложения, содержащие надписи, кнопки, текстовые поля и даже изображения, например, моя игра "Три в ряд" написана на этом. . .
|
Мысли в слух
kumehtar 18.11.2025
Кстати, совсем недавно имел разговор на тему медитаций с людьми. И обнаружил, что они вообще не понимают что такое медитация и зачем она нужна. Самые базовые вещи. Для них это - когда просто люди. . .
|
Создание Single Page Application на фреймах
krapotkin 16.11.2025
Статья исключительно для начинающих. Подходы оригинальностью не блещут.
В век Веб все очень привыкли к дизайну Single-Page-Application .
Быстренько разберем подход "на фреймах".
Мы делаем одну. . .
|
Фото: Daniel Greenwood
kumehtar 13.11.2025
|
Расскажи мне о Мире, бродяга
kumehtar 12.11.2025
— Расскажи мне о Мире, бродяга,
Ты же видел моря и метели.
Как сменялись короны и стяги,
Как эпохи стрелою летели.
- Этот мир — это крылья и горы,
Снег и пламя, любовь и тревоги,
И бескрайние. . .
|