Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
книги хакеры / Питер_Гудлиф_Ремесло_программиста_Практика_написания_хорошего_кода.pdf
Скачиваний:
16
Добавлен:
19.04.2024
Размер:
9.23 Mб
Скачать

 

 

 

 

hang

e

 

 

 

 

 

 

 

C

 

E

 

 

 

 

X

 

 

 

 

 

 

-

 

 

 

 

 

d

 

 

F

 

 

 

 

 

 

t

 

 

D

 

 

 

 

 

 

 

i

 

 

 

 

 

 

 

 

 

r

P

 

 

 

 

 

NOW!

o

 

 

 

 

 

 

 

 

 

 

 

 

BUY

 

 

 

 

 

 

to

 

 

 

 

 

w Click

 

 

 

 

 

m

 

 

 

 

 

 

w

 

 

 

 

 

 

 

 

 

 

w

 

 

 

 

 

 

 

o

 

 

.

 

 

 

 

 

.c

 

 

 

p

 

 

 

 

g

 

 

 

 

 

df

 

 

n

e

 

 

 

 

 

-xcha

 

 

 

 

 

 

 

 

hang

e

 

 

 

 

 

 

 

C

 

E

 

 

 

 

X

 

 

 

 

 

 

-

 

 

 

 

 

d

 

 

F

 

 

 

 

 

 

t

 

 

D

 

 

 

 

 

 

 

i

 

 

 

 

 

 

 

 

 

r

P

 

 

 

 

 

NOW!

o

 

 

 

 

 

 

 

 

 

 

 

 

BUY

 

 

 

 

 

 

to

 

 

 

 

 

w Click

 

 

 

 

 

m

 

 

 

 

 

 

w

 

 

 

 

 

 

 

 

 

 

w

 

 

 

 

 

 

 

o

 

 

.

 

 

 

 

 

.c

 

 

 

p

 

 

 

 

g

 

 

 

 

 

df

 

 

n

e

 

 

 

 

 

-x cha

 

 

 

 

ОТВЕТЫ И ОБСУЖДЕНИЕ

Принципы развития совершенного ума:

Изучайте искусство как науку. Изучайте науку как искусство. Развивайте свои чувства – в особенности учитесь видеть.

Проникнитесь пониманием того, что все вещи связаны между собой.

Леонардо Да Винчи

Эта часть содержит мои размышления по поводу вопросов, предлагае% мых в конце каждой главы. Это не набор простых ответов – очень ред% ко ответ заключается в да или нет. Сравните свои ответы с приведен% ными здесь.

Смысл вопросов в том, чтобы побудить вас мыслить, заставить глубже проникнуть в каждую тему и подстегнуть к совершенствованию своего умения программировать.

Если вы собираетесь продолжить чтение, только чтобы узнать «пра% вильный» ответ, не дав себе труда подумать над вопросом, я настоя% тельно советую вам не делать этого. Даже немного времени, потрачен% ного на размышление и оценку личной ситуации, окупится с лихвой. Как сказал Конфуций: «Я слышу и забываю. Я вижу и запоминаю. Я делаю и понимаю.»

Глава 1. Держим оборону

Вопросы для размышления

1. Можно ли переусердствовать с защитным кодом?

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

 

 

 

 

hang

e

 

 

 

 

 

 

C

 

E

 

 

 

X

 

 

 

 

 

-

 

 

 

 

 

d

 

F

 

 

 

 

 

 

t

 

D

 

 

 

 

 

 

 

i

 

 

 

 

 

 

 

 

r

P

 

 

 

 

 

NOW!

o

 

 

 

 

 

 

 

 

 

 

 

BUY

 

 

 

 

 

to

 

 

 

 

w Click

 

 

 

582m

 

 

 

 

w

 

 

 

 

 

 

 

 

 

w

 

 

 

 

 

 

 

o

 

.

 

 

 

 

 

.c

 

 

p

 

 

 

 

g

 

 

 

 

df

 

 

n

e

 

 

 

 

-xcha

 

 

 

 

 

 

 

hang

e

 

 

 

 

 

 

 

C

 

E

 

 

 

 

X

 

 

 

 

 

 

-

 

 

 

 

 

d

 

 

F

 

 

 

 

 

 

t

 

 

D

 

 

 

 

 

 

 

i

 

 

 

 

 

 

 

 

 

r

P

 

 

 

 

 

NOW!

o

 

 

 

 

 

 

 

 

 

 

 

 

BUY

 

 

 

 

 

 

to

 

 

 

 

 

Ответы и обсуждениеClick

 

 

 

 

 

m

 

 

 

 

 

 

w

 

 

 

 

 

 

 

o

 

 

w

 

 

 

 

 

 

 

 

w

 

 

 

 

 

 

.c

 

 

.

 

 

 

 

 

 

 

 

p

 

 

 

 

g

 

 

 

 

 

df

 

 

n

e

 

 

 

 

 

-x cha

 

 

 

 

2.Нужно ли добавлять операторы контроля в каждую точку, где выявле на и исправлена ошибка?

В принципе это неплохая практика. Но нужно подумать, где их стоит располагать. Очень часто ошибки возникают из%за нарушения контрак% та API. Если вы передали мусор в функцию, нужно поместить в эту функцию какую%то проверку предусловия, а не делать проверку в мес% те вызова. Если функция возвратила мусор, нужно либо исправить ее так, чтобы больше такого не происходило (и проверить исправление), либо написать какие%то проверки постусловий.

Полезнее для всякой найденной и исправленной ошибки добавить но% вый тест модуля.

3.Следует ли исключать из окончательных сборок операторы контроля посредством условной компиляции? Если нет, то какие контрольные операторы стоит оставить в окончательной сборке?

Некоторые очень эмоционально относятся к этой проблеме. Трудно дать однозначный ответ; есть много доводов «за» и «против». Часто встречаются совсем малозначительные проверки, которым не место в окончательном коде. Но некоторые операторы контроля могут ока% заться полезны и при реальной эксплуатации пакета.

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

Нужно помнить, что действительные проверки ошибок этапа исполне% ния нельзя удалять, и они не должны программироваться как операто% ры контроля.

4.Что обеспечивает лучшую защиту – обработка исключений или опера торы контроля в стиле C?

Исключения могут обеспечивать лучшую защиту. Они ведут себя осо% бым образом: когда исключение распространяется вверх по стеку вы% зовов, его можно перехватить и игнорировать, подавив таким образом его действие. Благодаря этому исключения оказываются более гибким инструментом. Игнорировать оператор assert, прерывающий выпол% нение программы, нельзя; операторы контроля – механизмы более низкого уровня.

5.Следует ли включать защитную проверку пред и постусловий в каж дую функцию или только при вызове важных функций?

Несомненно – в функцию. Тогда вам придется написать проверку всего один раз. Желание вынести проверку из функции может быть обосно% ванным, только если нужна повышенная гибкость, чтобы по%разному реагировать на невыполнение ограничения. Но выигрыш не столь убе% дителен в сравнении с резким увеличением сложности и возможности отказа.

 

 

 

 

hang

e

 

 

 

 

 

 

 

C

 

E

 

 

 

 

X

 

 

 

 

 

 

-

 

 

 

 

 

d

 

 

F

 

 

 

 

 

 

t

 

 

D

 

 

 

 

 

 

 

i

 

 

 

 

 

 

 

 

 

r

 

P

 

 

 

 

 

NOW!

o

 

 

 

 

 

 

 

 

 

 

 

 

 

BUY

 

 

 

 

 

 

to

 

 

 

 

 

w Click

 

 

 

Главаm

1. Держим оборону

 

 

 

 

w

 

 

 

 

 

 

 

 

 

 

w

 

 

 

 

 

 

 

o

 

 

.

 

 

 

 

 

.c

 

 

 

p

 

 

 

 

g

 

 

 

 

 

df

 

 

n

e

 

 

 

 

 

-xcha

 

 

 

 

 

 

 

 

hang

e

 

 

 

 

 

 

 

C

 

E

 

 

 

 

X

 

 

 

 

 

 

-

 

 

 

 

 

d

 

 

F

 

 

 

 

 

 

t

 

 

D

 

 

 

 

 

 

 

i

 

 

 

 

 

 

 

 

 

r

P

 

 

 

 

 

NOW!

o

 

 

 

 

 

 

 

 

 

 

 

 

BUY

 

 

 

 

 

 

to

 

 

 

 

 

583Click

 

 

 

 

 

m

 

 

 

 

 

 

w

 

 

 

 

 

 

 

o

 

 

w

 

 

 

 

 

 

 

 

w

 

 

 

 

 

 

.c

 

 

.

 

 

 

 

 

 

 

 

p

 

 

 

 

g

 

 

 

 

 

df

 

 

n

e

 

 

 

 

 

-x cha

 

 

 

 

6.Насколько ограничения соответствуют идеалу защитного средства? Каковы их недостатки?

Этот механизм далек от совершенства. Лишние ограничения могут быть просто паразитами или даже представлять собой помехи. Напри% мер, можно проверять ограничение на значение параметра функции i >= 0. Но гораздо лучше сделать i беззнаковым типом, чтобы ему нель% зя было присваивать отрицательные значения.

Ограничения, от которых нельзя избавиться, должны рассматривать% ся с определенной степенью недоверия: необходимо тщательно следить за побочными эффектами (операторы контроля могут иметь скрытые косвенные последствия) и вопросами синхронизации в отладочной и окончательной сборках, которые могут различаться в поведении. Операторы контроля должны быть логическими ограничениями, а не настоящими проверками времени исполнения, которые нельзя уда% лять. В код, защищающий от ошибок, могут вкрасться ошибки!

Но осторожное применение ограничений все же гораздо лучше, чем их отсутствие и беззащитность перед случаем.

7.Можно ли обойтись без защитного программирования?

a.Можно ли изобрести язык, который устранит необходимость в за щитном программировании? Как это сделать?

b.Следует ли из этого, что C и C++ порочны, поскольку они оставляют слишком много простора для возможных проблем?

В языки наверняка можно было бы ввести некоторые функции, кото% рые позволили бы избегать ошибок. Например, в C не проверяется ин% декс при доступе к элементам массива. В результате можно вызвать аварийное завершение программы, обратившись по недопустимому адресу памяти. Напротив, в среде исполнения Java значения индексов массивов всегда проверяются, поэтому там такой катастрофы произой% ти не может. (Недопустимые индексы все равно вызывают ошибку, но класс отказов лучше определен.)

Хотя список «усовершенствований», которые можно было бы ввести в либеральную спецификацию C (советую вам подумать и предложить их как можно больше), может быть длинным, вы никогда не приду% маете такой язык, который не требует защитного программирования. В функциях всегда нужно будет проверять параметры, а в классах все% гда будут нужны инварианты для проверки непротиворечивости их внутренних данных.

Несмотря на то, что C и C++ предоставляют богатые возможности для совершения ошибок, они также обладают огромной мощью и вырази% тельностью. Считать ли это пороком языка – дело вкуса. Это благодат% ная тема для начала религиозных споров.

8.Какого рода код не должен вызывать заботы о защитном программи ровании?

 

 

 

 

hang

e

 

 

 

 

 

 

C

 

E

 

 

 

X

 

 

 

 

 

-

 

 

 

 

 

d

 

F

 

 

 

 

 

 

t

 

D

 

 

 

 

 

 

 

i

 

 

 

 

 

 

 

 

r

P

 

 

 

 

 

NOW!

o

 

 

 

 

 

 

 

 

 

 

 

BUY

 

 

 

 

 

to

 

 

 

 

w Click

 

 

 

584m

 

 

 

 

w

 

 

 

 

 

 

 

 

 

w

 

 

 

 

 

 

 

o

 

.

 

 

 

 

 

.c

 

 

p

 

 

 

 

g

 

 

 

 

df

 

 

n

e

 

 

 

 

-xcha

 

 

 

 

 

 

 

hang

e

 

 

 

 

 

 

 

C

 

E

 

 

 

 

X

 

 

 

 

 

 

-

 

 

 

 

 

d

 

 

F

 

 

 

 

 

 

t

 

 

D

 

 

 

 

 

 

 

i

 

 

 

 

 

 

 

 

 

r

P

 

 

 

 

 

NOW!

o

 

 

 

 

 

 

 

 

 

 

 

 

BUY

 

 

 

 

 

 

to

 

 

 

 

 

Ответы и обсуждениеClick

 

 

 

 

 

m

 

 

 

 

 

 

w

 

 

 

 

 

 

 

o

 

 

w

 

 

 

 

 

 

 

 

w

 

 

 

 

 

 

.c

 

 

.

 

 

 

 

 

 

 

 

p

 

 

 

 

g

 

 

 

 

 

df

 

 

n

e

 

 

 

 

 

-x cha

 

 

 

 

Мне приходилось работать с людьми, которые отказывались вводить защитный код в старую программу, потому что она была настолько плоха, что их защита не принесла бы ощутимых результатов. С боль% шим трудом я удерживал себя от того, чтобы их поколотить.

Можно встать на ту точку зрения, что отдельная маленькая программа из одного файла или отладочная структура обойдутся без тщательного кода защиты или строгих ограничений. Но даже в этих случаях безза% ботность – это неряшливость. Мы должны стремиться к тому, чтобы постоянно занимать оборонительную позицию.

Вопросы личного характера

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

Готов поспорить, что вы проверяете не все. Очень легко пропустить код возврата некоторых функций, особенно когда их важность счита% ется не одинаковой. Много ли найдется программирующих на C, кто проверяет код возврата printf? И многие ли знают, что он вообще су% ществует?

2.Указываете ли вы пред и постусловия в описаниях функций?

a.Присутствуют ли они в неявном виде в описании работы функции?

b.Если пред и постусловия отсутствуют, отмечаете ли вы это явно в документации?

Каким бы очевидным ни казался вам контракт (из имени функции или ее описания), явная констатация ограничений снимает всякие не% доразумения; всегда помните, что областей для предположений долж% но быть как можно меньше. Явный текст «Предусловия: отсутству# ют» явно документирует контракт.

Конечно, не нужно повторять в каждой функции предусловие, являю% щееся глобальным. Это утомительно и скучно. Если всюду в API пред% полагается, что значения указателей не могут быть нулевыми, лучше написать это один раз в глобальной секции.

3.Многие компании на словах одобряют защитное программирование. Рекомендуется ли придерживаться этой стратегии в ваших условиях? Изучите исходные коды – соблюдаются ли рекомендации на практи ке? Насколько распространена проверка допущений с помощью опе раторов контроля? Насколько тщательно осуществляется проверка ошибок в каждой функции?

Очень редко в компаниях сочетаются культура отличного кода с долж% ным уровнем защиты. Рецензирование кода – хороший способ под% нять качество кода, создаваемого командой; чем больше глаз видят код, тем больше ошибок обнаруживается.