Урок 36. Литералы. Магические числа

   ⁄ 

 Обновлено 17 Апр 2017

  ⁄   

В C++ есть два вида констант: литеральные и символьные (символические). В этом уроке мы рассмотрим литеральные.

Литеральные константы

Литеральные константы (обычно просто литералы) – это значения, которые вставляются непосредственно в код. Они являются константами, так как изменить их значения нельзя. Например:

С литералами bool и int всё просто, а вот с литералами floating point есть два способа объявления:

Во второй форме, число после экспонента может быть и отрицательным:

Числовые литералы могут иметь суффиксы, которые определяют их типы. Эти суффиксы не являются обязательными, так как компилятор может из контекста сказать, какого типа константу вы хотите использовать.

Тип данных Суффикс Значение
int u или U unsigned int
int l или L long
int ul, uL, Ul, UL, lu, lU, Lu или LU unsigned long
int ll или LL long long
int ull, uLL, Ull, ULL, llu, llU, LLu или LLU unsigned long long
double f или F float
double l или L long double

Суффиксы есть даже для целочисленных типов (в основном ими не пользуются):

По умолчанию, тип литеральных констант с плавающей запятой — double. Для конвертации в тип float, можно использовать суффикс f или F:

C++ также поддерживает литералы string и char:

Литералы типа char работают, как и следует ожидать. А вот литералы string в C++ обрабатываются немного странно. На данный момент, вы можете использовать их для вывода текста с помощью std::cout, но не пытайтесь присваивать их переменным в качестве значений или передавать функциям — это либо не будет работать, либо будет работать не так, как вы ожидаете. Мы поговорим больше о C-style string (и о том, как с ним работать) в будущем.

Литералы хорошо использовать в коде до тех пор, пока их значения ясны. Это случаи присвоения значений переменным, выполнение математических операций или вывод текста в консоль.

Литералы в восьмеричной и шестнадцатеричной системе

В повседневной жизни, мы используем десятичную систему (decimal) счисления для разных подсчетов, которая состоит из цифр: 0, 1, 2, 3, 4, 5, 6, 7, 8 или 9. Она еще называется «основа 10», так как всего есть 10 возможных цифр (от 0 до 9). Считаем так: 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, … . По умолчанию числа в программах C++ рассматриваются как десятичные.

В двоичной системе (binary) всего 2 цифры: 0 и 1, «основа 2». Здесь подсчет ведется следующим образом: 0, 1, 10, 11, 100, 101, 110, 111, … .

Есть еще две другие системы: восьмеричная и шестнадцатеричная.

Восьмеричная система (octal) – «основа 8», доступны только такие цифры: 0, 1, 2, 3, 4, 5, 6 и 7. Считаем так: 0, 1, 2, 3, 4, 5, 6, 7, 10, 11, 12, … (примечание: 8 и 9 — нет, так что мы сразу же перескакиваем от 7 к 10).

Десятичная система 0 1 2 3 4 5 6 7 8 9 10 11
Восьмеричная система 0 1 2 3 4 5 6 7 10 11 12 13

Для использования восьмеричного литерала – добавляйте префикс 0:

Результат:

10

Почему 10 вместо 12? Потому что числа выводятся в десятичной системе, а 12 в восьмеричной системе = 10 в десятичной.

Эта система используется крайне редко и мы советуем её избегать.

Шестнадцатеричная система (hexadecimal) – «основа 16». Считаем так: 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, А, В, С, D, Е, F, 10, 11, 12, … .

Десятичная система 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
Шестнадцатеричная система 0 1 2 3 4 5 6 7 8 9 A B C D E F 10 11

Для использования шестнадцатеричного литерала – добавляйте префикс 0x.

Результат:

15

Поскольку в этой системе 16 разных значений, то одна шестнадцатеричная цифра занимает 4 бита. Следовательно, пара шестнадцатеричных цифр занимает целый байт.

Рассмотрим 32-битовое целое число, значение которого — 0011 1010 0111 1111 1001 1000 0010 0110. Из-за длины и повторения цифр, его сложно прочесть. В шестнадцатеричной системе, это же значение будет выглядеть так: 3A7F 9826. Такой удобный сжатый формат является преимуществом hexadecimal. Поэтому шестнадцатеричные значения часто используются для представления адресов памяти или необработанных значений памяти.

До C++ 14, использовать бинарный литерал – возможности нет. Тем не менее, шестнадцатеричная система и тут дает нам обходной путь:

Бинарные литералы и цифровой разделитель C++ 14

В C++ 14 мы можем использовать бинарные литералы, добавляя префикс 0b:

Поскольку длинные литералы читать трудно, то в C++ 14 появляется возможность использовать одинарную кавычку  в качестве цифрового разделителя.

Если ваш компилятор не поддерживает C++ 14, то использовать бинарные литералы и цифровой разделитель вы не сможете – получите ошибку.

Магические числа и почему они плохие

Рассмотрим следующий фрагмент кода:

Число 30, во фрагменте выше, называется магическим числом. Магическое число – это хорошо закодированный литерал (обычно, число) в середине кода, который не имеет никакого контекста. Что это 30 означает? Хоть вы и можете догадаться, что в данном случае это максимальное количество учеников на один класс — оно всё равно не до конца понятно. В более сложных программах, контекст подобных чисел разгадать намного сложнее, если только не будет отдельных комментариев для каждого из них.

Использование магических чисел является плохой практикой, так как в дополнение к тому, что они не предоставляют никакого контекста (для чего и почему они используются), они также могут создать проблемы, если их значения необходимо будет изменить. Предположим, школа купит новые парты, которые повысят количество учеников на класс с 30 до 35 — это нужно будет отобразить в нашей программе. Рассмотрим следующий фрагмент:

Чтобы обновить число учеников на класс, нам придется обновить константу с 30 на 35. Но как насчет вызова функции setMax(30)? 30 что аргумент и 30 что константа – это одно и то же? Если да, то и аргумент нужно будет обновить. Если нет, то его не следует трогать, иначе мы можем способствовать возникновению сбоя программы где-нибудь в другом месте. Если проводить автоматический глобальный поиск и замену, то можно ненароком изменить и аргумент функции setMax(), в то время, как его не следовало бы трогать. Поэтому вам придется просмотреть весь код, в поиске чисел со значением 30, а затем определить, нужно ли в каждом случае обновлять до 35 или нет. Это займет очень много времени, к тому же вероятность возникновения новых ошибок повышается в разы.

К счастью, есть лучший вариант – использовать символьные константы. О них мы поговорим в следующем уроке.

Правило: Не используйте магические числа в вашем коде.

Оценить статью:

Звёзд: 1Звёзд: 2Звёзд: 3Звёзд: 4Звёзд: 5 (12 оценок, среднее: 4,92 из 5)
Загрузка...
Поделиться в:
Подписаться на обновления:

Добавить комментарий

Ваш e-mail не будет опубликован. Обязательные поля помечены *