Материал: Руководство по стилю программирования и конструированию по

Внимание! Если размещение файла нарушает Ваши авторские права, то обязательно сообщите нам

ГЛАВА 11 Сила имен переменных
281
Ключевые моменты

Выбор хороших имен переменных — одно из главных условий понятности программы. С отдельными типами переменных — например, с индексами цик- лов и переменными статуса — связаны свои принципы именования.

Имена должны быть максимально конкретны. Имена, которые из-за невыра- зительности или обобщенности можно использовать более чем с одной целью,
обычно являются плохими.

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

Над каким бы проектом вы ни работали, вам следует принять конвенцию име- нования переменных. При выборе типа конвенции следует учитывать размер программы и число работающих над ней программистов.

Современные языки программирования позволяют отказаться от сокращения имен. Если вы все-таки сокращаете имена, регистрируйте аббревиатуры в сло- варе проекта или используйте стандартизированные префиксы.

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

282
ЧАСТЬ III Переменные
Г Л А В А 1 2
Основные типы данных
Содержание

12.1. Числа в общем

12.2. Целые числа

12.3. Числа с плавающей запятой

12.4. Символы и строки

12.5. Логические переменные

12.6. Перечислимые типы

12.7. Именованные константы

12.8. Массивы

12.9. Создание собственных типов данных (псевдонимы)
Связанные темы

Присвоение имен данным: глава 11

Нестандартные типы данных: глава 13

Общие вопросы использования переменных: глава 10

Описание форматов данных: подраздел «Размещение объявлений данных»
раздела 31.5

Документирование переменных: подраздел «Комментирование объявлений дан- ных» раздела 32.5

Создание классов: глава 6
Основные типы данных являются базовыми блоками для построения остальных типов данных. Эта глава содержит советы по применению чисел вообще, целых чисел, чисел с плавающей запятой, символов и строк, логических переменных,
перечислимых типов, именованных констант и массивов. В заключительном раз- деле этой главы рассказано о создании собственных типов данных.
Эта глава содержит рекомендации по предупреждению главных ошибок в приме- нении основных типов данных. Если вы уже ознакомились с основами, перехо- дите к концу главы, к обзору перечня допускаемых ошибок, а также к обсужде- нию нестандартных типов данных в главе 13.
http://cc2e.com/1278

ГЛАВА 12 Основные типы данных
283
12.1. Числа в общем
Далее дано несколько рекомендаций, позволяющих сократить число ошибок при использовании чисел.
Избегайте «магических чисел» Магические числа — это обычные числа, такие как
100 или 47524, которые появля- ются в программе без объяснений. Если вы программируе- те на языке, поддерживающем именованные константы, ис- пользуйте их вместо магических чисел. Если вы не можете применить именованные константы, применяйте глобальные переменные, когда это возможно.
Исключение магических чисел дает три преимущества.

Изменения можно сделать более надежно. Если вы используете именованные константы, нет нужды искать каждое из чисел
100, и вы не измените по ошиб- ке те из этих чисел, что ссылаются на что-либо иное.

Изменения сделать проще. Когда максимальное число элементов меняется со
100 на 200, используя магические числа, вы должны найти каждое число 100
и изменить его на
200. Если вы используете 100+1 или 100-1, вы также долж- ны найти и изменить все числа
101 и 99 на 201 и 199 соответственно. При использовании именованных констант вы просто меняете определение кон- станты со
100 на 200 в одном месте.

Ваша программа лучше читается. Конечно, в выражении:
for i = 0 to 99 do ...
можно предположить, что
99 определяет максимальное число элементов. А вот выражение:
for i = 0 to MAX_ENTRIES-1 do ...
не оставляет на этот счет сомнений. Даже если вы уверены, что это число ни- когда не изменится, применяя именованные константы, вы получите более читабельную программу.
Применяйте жестко заданные нули и единицы по необходимости Зна- чения
0 и 1 используются для инкремента, декремента, а также в начале циклов при нумерации первого элемента массива.
0 в конструкции:
for i = 0 to CONSTANT do ...
вполне приемлем, так же как
1 в выражении:
total = total + 1
Вот хорошее правило: используйте в программе как константы только
0 и 1, а любые другие числа определите как литералы с понятными именами.
Ошибки деления на ноль Каждый раз, когда вы пользуетесь символом деления
(
/ в большинстве языков), думайте о том, может ли в знаменателе оказаться 0. Если такая возможность существует, напишите код, предупреждающий появление ошиб- ки деления на 0.
Перекрестная ссылка О приме- нении именованных констант вместо магических чисел см.
раздел 12.7.

284
ЧАСТЬ III Переменные
Выполняйте преобразования типов понятно Убедитесь, что кто-нибудь, чи- тая вашу программу, поймет преобразования между разными типами данных,
которые в ней встречаются. На языке C++ вы могли бы написать:
y = x + (float) i а на Microsoft Visual Basic:
y = x + CSng( i )
Эта практика поможет обеспечить однозначность ваших преобразований — раз- ные компиляторы по-разному конвертируют, а при таком подходе вы гарантиро- ванно получите то, что ожидали.
Избегайте сравнений разных типов Если x — число с плавающей запятой, а
i — целое, проверка:
if ( i = x ) then ...
почти гарантированно не сработает. К тому времени, когда компилятор опреде- лит каждый тип, который он хочет задействовать для сравнения, преобразует один из типов в другой, произведет ряд округлений и вычислит ответ, вы будете рады,
если ваша программа вообще работает. Сделайте преобразования вручную, так чтобы компилятор мог сравнить два числа одного и того же типа, и точно знай- те, что нужно сравнивать.
Обращайте внимание на предупреждения вашего компилято-
ра Многие современные компиляторы сообщают о наличии разных типов чисел в одном выражении. Обращайте на это внимание! Каждый программист рано или поздно просит кого-нибудь помочь выследить надоедли- вую ошибку, а выясняется, что о ней все время предупреждал компилятор. Про- фессионалы высокого класса пишут свои программы так, чтобы исключить все предупреждения компилятора. Легче предоставить работу компилятору, чем вы- полнять ее самому.
12.2. Целые числа
Учитывайте следующие рекомендации при применении целых чисел.
Проверяйте целочисленность операций деления Когда используются целые числа, выражение 7/10 не равно 0,7. Оно обычно равно 0 или минус бесконечно- сти, или ближайшему целому, или… ну, вы понимаете. Результат зависит от выб- ранного языка. Это же относится и к промежуточным результатам. В реальном мире
10 * (7/10) = (10*7) / 10 = 7. Но не в мире целочисленной арифметики. 10 * (7/10)
равно 0, потому что целочисленное деление (7/10) равно 0. Простейший способ исправить положение — преобразовать его так, чтобы операции деления выпол- нялись последними: (10*7) / 10.
Проверяйте переполнение целых чисел При выполнении умножения или сло- жения необходимо принимать во внимание наибольшие возможные значения це- лых чисел. Для целого числа без знака это обычно 2 32
–1, а иногда и 2 16
–1, или 65 535.
Проблема возникает, когда вы умножаете два числа, в результате чего получается
Перекрестная ссылка Вариант этого примера см. в разделе 12.3.

1   ...   32   33   34   35   36   37   38   39   ...   104
ГЛАВА 12 Основные типы данных
285
число большее, чем максимально возможное целое. Скажем, если вы умножаете
250 * 300, правильным ответом будет 75 000. Но если максимальное целое — 65 535,
то, возможно, из-за переполнения вы получите 9464 (75 000 – 65 536 = 9464). Вот интервалы значений для часто встречающихся целых типов (табл. 12-1):
Табл. 12-1. Интервалы значений некоторых целых типов
Целый тип
Интервал
8-битный со знаком
От –128 до 127 8-битный без знака
От 0 до 255 16-битный со знаком
От –32 768 до 32 767 16-битный без знака
От 0 до 65 535 32-битный со знаком
От –2 147 483,648 до 2 147 483 647 32-битный без знака
От 0 до 4 294 967 295 64-битный со знаком
От –9 223 372 036 854 775 808 до 9 223 372 036 854 775 807 64-битный без знака
От 0 до 18 446 744 073 709 551 615
Простейший способ предотвращения целочисленного переполнения — просмотр каждого члена арифметического выражения с целью представить наибольшее возможное значение, которое он может принимать. Так, если в целочисленном выражении
m = j * k, наибольшим значением для j будет 200, а для k — 25, то мак- симальным значением для
m будет 200 * 25 = 5 000. Для 32-разрядных машин это вполне допустимо, так как максимальным целым является 2 147 483 647. С другой стороны, если максимально возможное значение для
j — это 200 000, а для k
100 000, то значение
m может достигать 200 000 * 100 000 = 20 000 000 000. Это уже неприемлемо, так как 20 000 000 000 больше, чем 2 147 483 647. В этом слу- чае для размещения наибольшего возможного значения
m вам придется исполь- зовать 64-битные целые или числа с плавающей запятой.
Кроме того, учитывайте будущее развитие программы. Если
m никогда не будет больше 5 000 — отлично. Но если ожидается, что
m будет постоянно расти на протяжении нескольких лет, примите это во внимание.
Проверяйте на переполнение промежуточные результаты Число, полу- чаемое в конце вычислений, — не единственное, о котором следует беспокоить- ся. Представьте, что у вас есть такой код:
Пример переполнения промежуточных результатов (Java)
int termA = 1000000;
int termB = 1000000;
int product = termA * termB / 1000000;
System.out.println( “( “ + termA + “ * “ + termB + “ ) / 1000000 = “ + product );
Вы можете подумать, что значение
Product вычисляется как (100 000*100 000) /
100 000 и поэтому равно 100 000. Но программе приходится вычислять проме- жуточное значение
100 000*100 000 до того, как будет выполнено деление на
100 000, а это значит, что нужно хранить такое большое число, как
1 000 000 000 000
. Угадайте, что получится? Вот результат:
( 1000000 * 1000000 ) / 1000000 = -727

286
ЧАСТЬ III Переменные
Если значение целых чисел в вашей системе не превышает 2 147 483 647, проме- жуточный результат слишком велик для целого типа данных. В такой ситуации промежуточный результат, который должен быть равен
1 000 000 000 000, на са- мом деле равен
727 379 968, поэтому, когда вы делите его на 100 000, вы получа- ете -
727 вместо 100 000.
Вы можете решить проблему переполнения промежуточных результатов так же,
как и в случае целочисленного переполнения: изменив тип на длинное целое или число с плавающей запятой.
12.3. Числа с плавающей запятой
Главная особенность применения чисел с плавающей запятой в том, что многие дробные десятичные числа не могут быть точно представлены с помощью нулей и единиц, используемых в цифровом компьютере.
В бесконечных десятичных дробях, таких как 1/3 или 1/7, обычно сохраняется только 7 или 15 цифр после запятой. В моей версии Microsoft Visual Basic 32-бит- ное представление дроби 1/3 в виде числа с плавающей запятой равно 0,33333330.
То есть точность ограничена 7 цифрами. Такая точность достаточна для большин- ства случаев, но все же способна иногда вводить в заблуждение.
Вот несколько рекомендаций по использованию чисел с плавающей запятой.
Избегайте сложения и вычитания слишком разных по
размеру чисел Для 32-битной переменной с плавающей запятой сумма 1 000 000,00 + 0,1, вероятно, будет равна
1 000 000,00, так как в 32 битах недостаточно значимых цифр, чтобы охватить интервал между 1 000 000 и 0,1. Ана- логично 5 000 000,02 – 5 000 000,01, вероятно, равно 0,0.
Решение? Если вам нужно складывать настолько разные по величине числа, сна- чала отсортируйте их, а затем складывайте, начиная с самых маленьких значений.
Аналогично, если вам надо сложить бесконечный ряд значений, начните с наи- меньшего члена, т. е. суммируйте члены в обратном порядке. Это не решит про- блемы округления, но минимизирует их. Многие алгоритмические книги предла- гают решения для таких случаев.
Избегайте сравнений на равенство Числа с плавающей запятой, которые должны быть равны, на самом деле рав- ны не всегда. Главная проблема в том, что два разных спо- соба получить одно и то же число не всегда приводят к одинаковому результату. Так, если 10 раз сложить 0,1, то 1,0 получается только в редких случаях. Следующий пример содержит две переменных (
nominal и sum),
которые должны быть равны, но это не так.
Пример неправильного сравнения чисел с плавающей точкой (Java)
Переменная nominal — 64-битное вещественное число.
double nominal = 1.0;
double sum = 0.0;
Перекрестная ссылка Книги,
содержащие алгоритмы реше- ния этих проблем, см. в подраз- деле «Дополнительные ресур- сы» раздела 10.1.
1 равен 2 для достаточно боль- ших значений 1.
Аноним
>
Источник: https://files.student-it.ru/previewfile/206183