Язык С. Мастерство программирования. Принципы, практики и паттерны
Покупка
Новинка
Тематика:
Программирование на C и C++
Издательство:
ДМК Пресс
Автор:
Прешерн Кристофер
Перевод:
Слинкин Алексей Александрович
Год издания: 2023
Кол-во страниц: 302
Дополнительно
Вид издания:
Практическое пособие
Уровень образования:
Дополнительное профессиональное образование
ISBN: 978-6-01810-340-7
Артикул: 856517.01.99
В этом практическом руководстве начинающие и опытные программисты на C найдут наставления по принятию проектных решений, включая пошаговое применение паттернов к сквозным примерам.
Автор, один из ведущих членов сообщества паттернов проектирования, объясняет, как организовать программу на C, как обрабатывать ошибки и проектировать гибкие интерфейсы. В части I вы научитесь реализовывать проверенные практикой подходы к программированию на языке C; часть II показывает, как паттерны программирования на C применяются к реализации более крупных программ.
Тематика:
ББК:
УДК:
ОКСО:
- ВО - Бакалавриат
- 09.03.01: Информатика и вычислительная техника
- 09.03.02: Информационные системы и технологии
ГРНТИ:
Скопировать запись
Фрагмент текстового слоя документа размещен для индексирующих роботов
Прешерн К. Язык С Мастерство программирования Принципы, практики и паттерны
Fluent C Principles, Practices, and Patterns Christopher Preschern Beijing • Cambridge • Farnham • Köln • Sebastopol • Tokyo
Прешерн К. Язык С Мастерство программирования Принципы, практики и паттерны
УДК 004.4 ББК 32.372 П71 П71 Прешерн К. Язык С. Мастерство программирования. Принципы, практики и паттерны / пер. с англ. А. А. Слинкина – М.: ДМК Пресс, 2023. – 300 с.: ил. ISBN 978-6-01810-340-7 В этом практическом руководстве начинающие и опытные программисты на C найдут наставления по принятию проектных решений, включая пошаговое применение паттернов к сквозным примерам. Автор, один из ведущих членов сообщества паттернов проектирования, объясняет, как организовать программу на C, как обрабатывать ошибки и проектировать гибкие интерфейсы. В части I вы научитесь реализовывать проверенные практикой подходы к программированию на языке C; часть II показывает, как паттерны программирования на C применяются к реализации более крупных программ. Copyright © 2023 Books.kz Limited Liability Partnership. All rights reserved. Все права защищены. Любая часть этой книги не может быть воспроизведена в какой бы то ни было форме и какими бы то ни было средствами без письменного разрешения владельцев авторских прав. Материал, изложенный в данной книге, многократно проверен. Но, поскольку вероятность технических ошибок все равно существует, издательство не может гарантировать абсолютную точность и правильность приводимых сведений. В связи с этим издательство не несет ответственности за возможные ошибки, связанные с использованием книги. ISBN 978-1-49210-973-3 (англ.) © Christopher Preschern, 2023 ISBN 978-6-01810-340-7 (казах.) © Оформление, перевод на русский язык, издание, Books.kz, 2023
Оглавление Предисловие....................................................................................................8 ЧАСТЬ I. Паттерны на C...............................................................................25 Глава 1. Обработка ошибок.........................................................................26 Сквозной пример..............................................................................................27 Разбиение функции................................................................................................29 Проверка условий....................................................................................................32 Принцип самурая....................................................................................................35 Переход к обработке ошибки.................................................................................39 Запись об очистке....................................................................................................42 Объектная обработка ошибок................................................................................45 Резюме................................................................................................................48 Для дополнительного чтения...........................................................................49 Что дальше.........................................................................................................50 Глава 2. Возврат информации об ошибке.................................................51 Сквозной пример..............................................................................................52 Возврат кода состояния..........................................................................................54 Возврат существенной информации об ошибке...................................................61 Специальное возвращаемое значение..................................................................67 Протоколирование ошибок....................................................................................70 Резюме................................................................................................................77 Для дополнительного чтения...........................................................................77 Что дальше.........................................................................................................77 Глава 3. Управление памятью.....................................................................78 Хранение данных и проблемы с динамической памятью..............................80 Сквозной пример....................................................................................................83 Сначала стек............................................................................................................83 Вечная память.........................................................................................................86 Последствия.............................................................................................................88 Отложенная очистка...............................................................................................90 Единоличное владение...........................................................................................94 Обертка выделения.................................................................................................97 Проверка указателя...............................................................................................102 Пул памяти............................................................................................................105 Резюме..............................................................................................................111 Для дополнительного чтения.........................................................................111 Что дальше.......................................................................................................112 Глава 4. Возврат данных из C-функций...................................................113 Сквозной пример............................................................................................115 Возвращаемое значение.......................................................................................116
6 Оглавление Выходные параметры...........................................................................................119 Агрегат...................................................................................................................123 Неизменяемый экземпляр...................................................................................128 Буфер, принадлежащий вызывающей стороне..................................................131 Вызываемая сторона выделяет память...............................................................135 Резюме..............................................................................................................139 Что дальше.......................................................................................................140 Глава 5. Время жизни и владение данными..........................................141 Сквозной пример............................................................................................143 Программный модуль без состояния...................................................................144 Программный модуль с глобальным состоянием...............................................148 Экземпляр, принадлежащий вызывающей стороне..........................................152 Разделяемый экземпляр.......................................................................................158 Резюме..............................................................................................................164 Для дополнительного чтения.........................................................................165 Что дальше.......................................................................................................166 Глава 6. Гибкие API......................................................................................167 Сквозной пример............................................................................................169 Заголовочные файлы............................................................................................169 Описатель..............................................................................................................172 Динамический интерфейс....................................................................................176 Управление функцией..........................................................................................179 Резюме..............................................................................................................183 Для дополнительного чтения.........................................................................183 Что дальше.......................................................................................................184 Глава 7. Гибкие интерфейсы итераторов.................................................185 Сквозной пример............................................................................................187 Доступ по индексу.................................................................................................188 Курсор.....................................................................................................................192 Итератор обратного вызова.................................................................................197 Резюме..............................................................................................................202 Для дополнительного чтения.........................................................................203 Что дальше.......................................................................................................204 Глава 8. Организация файлов в модульных программах....................205 Сквозной пример............................................................................................207 Охрана включения................................................................................................209 Каталоги программных модулей.........................................................................212 Глобальный каталог include..................................................................................217 Автономный компонент.......................................................................................221 Копия API...............................................................................................................226 Резюме..............................................................................................................235 Что дальше.......................................................................................................235 Глава 9. Бегство из ада #ifdef....................................................................236 Сквозной пример............................................................................................238 Избегание вариантов............................................................................................240
Оглавление 7 Изолированные примитивы................................................................................243 Атомарные примитивы........................................................................................246 Уровень абстракции..............................................................................................250 Разделение реализаций вариантов......................................................................255 Резюме..............................................................................................................261 Для дополнительного чтения.........................................................................261 Что дальше.......................................................................................................262 ЧАСТЬ II. Истории о паттернах................................................................263 Глава 10. Реализация протоколирования...............................................264 История о паттернах.......................................................................................264 Организация файлов.............................................................................................265 Центральная функция протоколирования..........................................................266 Фильтрация источника сообщений.....................................................................267 Условное протоколирование................................................................................269 Несколько мест протоколирования.....................................................................270 Протоколирование в файл....................................................................................272 Кросс-платформенная обработка файлов...........................................................273 Использование средства протоколирования......................................................277 Резюме..............................................................................................................277 Глава 11. Построение системы управления пользователями.............279 История о паттернах.......................................................................................279 Организация данных............................................................................................279 Организация файлов.............................................................................................281 Аутентификация: обработка ошибок..................................................................282 Аутентификация: протоколирование ошибок....................................................284 Добавление пользователей: обработка ошибок.................................................285 Итерирование........................................................................................................287 Применение системы управления пользователями...........................................290 Резюме..............................................................................................................291 Глава 12. Заключение.................................................................................293 Чему вы научились..........................................................................................293 Для дополнительного чтения.........................................................................293 Заключительные замечания...........................................................................294 Об авторе.....................................................................................................295 Об иллюстрации на обложке....................................................................295 Предметный указатель..............................................................................296
Предисловие Вы купили эту книгу, чтобы поднять свои навыки программирования на новый уровень. И это правильно, потому что вам, безусловно, пригодятся излагаемые в ней практические знания. Если у вас имеется большой опыт программирования на C, то вы в деталях узнаете, как принимаются хорошие проектные решения и какие у них есть плюсы и минусы. Если вы только начинаете знакомиться с C, то найдете здесь руководство по принятию решений и на примерах кода увидите, как эти решения применяются для построения больших программ. В книге есть ответы на вопросы о том, как структурировать C-программу, как обрабатывать ошибки и как проектировать гибкие интерфейсы. Когда вы больше узнаёте о программировании на C, начинают возникать разные вопросы, например: • следует ли возвращать имеющуюся информацию об ошибке? • следует ли использовать для этой цели глобальную переменную errno? • что лучше: немного функций с большим числом параметров или наоборот? • как построить гибкий интерфейс? • как реализовать базовые вещи, например итератор? Для объектно ориентированных языков на большую часть этих вопросов почти исчерпывающий ответ дает книга «банды четырех»: Erich Gamma, Richard Helm, Ralph Johnson, John Vlissides «Design Patterns: Elements of Reusable Object-Oriented Software»1. Паттерны проектирования дают программисту проверенные опытом рекомендации, как должны взаимодействовать между собой объекты и как они связаны отношением владения. Кроме того, они показывают, как следует группировать объекты. Однако на процедурных языках типа C большинство этих паттернов проектирования невозможно реализовать так, как описано «бандой четырех». В С нет встроенных объектно ориентированных механизмов. Наследование или полиморфизм можно эмулировать, но это не лучшее решение, потому что такой код будет непонятен программистам, привыкшим к программированию на C, но не владеющим программированием на объектно ориентированных языках типа C++ и незнакомым с использованием таких концепций, как наследование и полиморфизм. Такие программисты хотели бы придерживаться стиля программирования на C, к которому привыкли. Однако к нему применимы не все объектно ориентированные рекомендации или, по крайней мере, конкретная реализация идеи паттерна проектирования не годится для не объектно ориентированного языка. 1 Э. Гамма, Р. Хелм, Р. Джонсон, Дж. Влиссидес. «Паттерны объектно ориентированного проектирования». Питер, 2022.
Зачем я написал эту книгу 9 Итак, ситуация выглядит следующим образом: мы хотим писать на C, но не можем напрямую использовать большую часть знаний, документированных в виде паттернов проектирования. В этой книге показано, как преодолеть разрыв и практически реализовать эти знания на языке программирования C. Зачем я написал эту книгу Теперь я хочу рассказать, почему знания, собранные в этой книге, оказались столь важными для меня и почему их так трудно отыскать. В школе я изучал C в качестве первого языка программирования. Как и любой начинающий программист на C, я удивлялся, почему нумерация элементов массива начинается с 0, и наугад пытался поместить операторы * и & в нужное место, чтобы заставить работать магию указателей. В университете я узнал, как в действительности работают синтаксические конструкции C и как они транслируются в аппаратные биты и байты. Вооруженный этими знаниями, я смог писать небольшие программы, которые работали очень хорошо. Но я по-прежнему не понимал, почему более длинный код выглядит именно так, а не иначе, и, уж конечно, не мог сам придумать решения вроде: typedef struct INTERNAL_DRIVER_STRUCT* DRIVER_HANDLE; typedef void (*DriverSend_FP)(char byte); typedef char (*DriverReceive_FP)(); typedef void (*DriverIOCTL_FP)(int ioctl, void* context); struct DriverFunctions { DriverSend_FP fpSend; DriverReceive_FP fpReceive; DriverIOCTL_FP fpIOCTL; }; DRIVER_HANDLE driverCreate(void* initArg, struct DriverFunctions f); void driverDestroy(DRIVER_HANDLE h); void sendByte(DRIVER_HANDLE h, char byte); char receiveByte(DRIVER_HANDLE h); void driverIOCTL(DRIVER_HANDLE h, int ioctl, void* context); При изучении этого кода возникает много вопросов: • зачем нужны указатели на функции в struct? • зачем функциям нужен этот DRIVER_HANDLE? • что такое IOCTL и почему бы не написать вместо этого отдельные функции? • зачем нужны явные функции создания и уничтожения? Эти вопросы появились, когда я начал писать производственные приложения.
10 Предисловие Я то и дело сталкивался с ситуациями, когда понимал, что мне не хватает знаний о C; например, как реализовать итератор или как обрабатывать ошибки в функциях. Я осознавал, что синтаксис-то я освоил, но понятия не имею, как им правильно воспользоваться. Я пытался чего-то добиться, но все получалось коряво или не получалось вовсе. Мне были необходимы рекомендации, показывающие, как решать конкретные задачи на языке C. Например: • как проще всего захватывать и освобождать ресурсы? • можно ли использовать goto для обработки ошибок? • следует ли сразу проектировать интерфейс гибким или лучше изменять его, когда возникнет необходимость? • следует ли использовать макрос assert, или нужно возвращать код ошибки? • как реализовать итератор на C? Для меня оказалось неожиданным открытием, что, хотя у моих опытных коллег было много различных ответов на эти вопросы, никто не смог направить меня туда, где такие проектные решения были документированы вместе с описанием их плюсов и минусов. Поэтому я обратился к интернету и снова испытал удивление: оказалось очень трудно найти убедительные ответы на эти вопросы, хотя язык C существует уже не один десяток лет. Я обнаружил, что, несмотря на изобилие литературы по основам и синтаксису языка C, нет почти ничего о продвинутом программировании и о том, как писать на C красивый код, который выдержит испытание производственным приложением. И вот тут в игру вступает эта книга. Она поможет вам отточить свои навыки программирования на C и перейти от простеньких программок к большим системам, в которых ошибки обрабатываются должным образом и которые обладают достаточной гибкостью, чтобы быть готовыми к будущим изменениям требований и проекта. В этой книге используется концепция паттернов проектирования, чтобы познакомить вас со всеми шагами принятия решений и оценкой их достоинств и недостатков. Эти паттерны применяются к сквозным примерам когда, чтобы показать, как код эволюционирует и почему принимает именно такую, а не иную конечную форму. Основы паттернов Рекомендации по проектированию в этой книге приводятся в форме паттернов. Идея представлять знания и передовые практики в виде паттернов исходит от архитектора Кристофера Александра, который высказал ее в книге «The Timeless Way of Building» (Oxford University Press, 1979). Он использует небольшие проверенные временем фрагменты для решения важнейшей проблемы в своей области: как проектировать и возводить города. Подход на основе паттернов переняли разработчики программного обеспечения, и теперь проводятся конференции типа Pattern Languages of Programs (PLoP), имеющие целью расширить наши знания о паттернах. В особенности книга «банды четы