Язык C: константы и литералы
Константы — фиксированные величины, которые не изменяются во время выполнения программы. Эти фиксированные величины также называются литералами.
Константы могут относиться к любому из основных типов данных, например:
- целочисленная константа;
- константа с плавающей точкой;
- символьная константа;
- строковый литерал.
Используются также перечислимые константы.
С константами обращаются так же, как и с обычными переменными. Только значения констант не могут быть изменены после их определения.
Целочисленные литералы
Целочисленный литерал может быть десятичной, восьмеричной или шестнадцатеричной константой. Префикс определяет основание (радикс) целочисленной константы:
- 0x или 0X — шестнадцатеричной;
- 0 — восьмеричной;
- отсутствие префикса — десятичной.
Целочисленный литерал может также иметь суффикс. Он представляет собой комбинацию букв U и L, означающих целое беззнакового и длинного типа (соответственно). Суффикс может быть прописной или строчной буквой и располагаться в любом порядке.
Вот несколько примеров целочисленных литералов:
Ниже приведены другие примеры различных типов целочисленных литералов:
Литералы с плавающей точкой
Литерал с плавающей точкой состоит из целой части, десятичной точки, дробной части и экспоненты. Литералы с плавающей точкой можно представлять либо в десятичной форме, либо в экспоненциальной.
При представлении десятичной формы включают десятичную точку, экспоненту либо и то, и другое; а при представлении экспоненциальной формы — целую часть, дробную часть либо обе части. Знаковая экспонента обозначается символом e или E.
Вот примеры литералов с плавающей точкой:
Символьные константы
Символьные литералы заключаются в одинарные кавычки; например, ‘x’ может храниться в простой переменной типа char.
Символьный литерал может быть:
- обычным символом (например, ‘x’);
- управляющей последовательностью (например, ‘\t’);
- универсальным символом (например, ‘\u02C0’).
В языке С есть определенные символы, которые имеют особое значение, когда им предшествует обратный слэш, например, новая строка (\n) или табуляция (\t).
Вот список таких кодов управляющей последовательности:
- \\ — символ \
- \’ — символ ‘
- \” — символ “
- \? — символ ?
- \a — звуковой сигнал
- \b — возврат на одну позицию (backspace)
- \f — смена страницы
- \n — новая строка
- \r — возврат каретки
- \t — горизонтальная табуляция
- \v — вертикальная табуляция
- \ooo — восьмеричное число (от одной до трех цифр)
- \xhh … … — шестнадцатеричное число (из одной или нескольких цифр)
Ниже приведен пример, показывающий несколько символов управляющей последовательности:
Когда приведенный выше код компилируется и выполняется, выдается следующий результат:
Строковые литералы
Строковые литералы (константы) заключаются в двойные кавычки “”. Строка содержит символы, похожие на символьные литералы:
- обычные символы;
- управляющие последовательности;
- универсальные символы.
Можно разбить длинную строку на несколько строк, используя строковые литералы и разделяя их пробельными символами.
Вот примеры строковых литералов. Все три формы являются идентичными строками:
Определение констант
В языке С есть два простых способа определения констант:
- Использование препроцессора #define.
- Использование ключевого слова const.
Препроцессор #define
Ниже приведена форма использования препроцессора #define для определения константы:
Следующий пример детально объясняет эту форму:
Когда приведенный выше код компилируется и выполняется, выдается следующий результат:
Ключевое слово const
Префикс const используется для объявления констант с определенным типом следующим образом:
Пример, указанный ниже, детально объясняет эту форму:
Когда приведенный выше код компилируется и выполняется, выдается следующий результат:
Обратите внимание: хорошей практикой программирования является определение констант в ЗАГЛАВНЫХ БУКВАХ.
4.13 – Литералы
В программировании константа – это фиксированное значение, которое нельзя изменять. В C++ есть два типа констант: литеральные константы и символьные константы. В этом уроке мы рассмотрим литеральные константы, а в следующем – символьные константы.
Литеральные константы (обычно называемые просто литералами) – это значения, вставленные непосредственно в код. Например:
Они являются константами, потому что их значения не могут быть изменены динамически (сначала вы должны изменить их, а затем перекомпилировать программу, чтобы изменение вступило в силу).
Так же, как у объектов есть тип, тип есть и у всех литералов. Тип литерала предполагается из значения и формата самого литерала.
| Значение литерала | Примеры | Тип по умолчанию |
|---|---|---|
| целое число | 5, 0, -3 | int |
| логическое значение | true , false | bool |
| число с плавающей запятой | 3.4, -2.2 | double (не float ) |
| символ | ' a ' | char |
| строка в стиле C | " Hello, world! " | const char[14] |
Суффиксы литералов
Если тип литерала по умолчанию не соответствует необходимому, вы можете изменить тип литерала, добавив суффикс:
| Тип данных | Суффикс | Назначение |
|---|---|---|
| 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 ):
Начинающие программисты часто не понимают, почему следующий код работает не так, как ожидалось:
Поскольку у 4.1 нет суффикса, он рассматривается как литерал типа double , а не как литерал типа float . Когда C++ определяет тип литерала, ему всё равно, что вы делаете с литералом (например, в данном случае используете его для инициализации переменной float ). Следовательно, 4.1 необходимо преобразовать из double в float , прежде чем его можно будет присвоить переменной f , и это может привести к потере точности.
Литералы можно использовать в коде C++, если их значения понятны. Чаще всего это происходит при использовании для инициализации или присвоения значения переменной, выполнения математических операций или вывода текста на экран.
Строковые литералы
В уроке «4.11 – Символы» мы определили строку как набор последовательных символов. C++ поддерживает строковые литералы:
Строковые литералы в C++ по историческим причинам обрабатываются очень странно. На данный момент можно использовать строковые литералы для печати текста с помощью std::cout , но не пытайтесь назначать их переменным или передавать их функциям – это либо не сработает, либо будет работать не так, как вы ожидаете. О строках в стиле C (и о том, как обойти все эти странные проблемы) мы поговорим подробнее в будущих уроках.
Экспоненциальная запись для числовых литералов с плавающей запятой
Есть два разных способа объявить литералы с плавающей точкой:
Во второй форме число после экспоненты может быть отрицательным:
Литералы в восьмеричной и шестнадцатеричной системах счисления
В повседневной жизни мы считаем, используя числа в десятичной системе счисления, где каждая цифра может быть 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++ считаются десятичными.
В двоичной системе счисления всего 2 цифры: 0 и 1, поэтому она называется «с основанием 2». В двоичном формате мы считаем так: 0, 1, 10, 11, 100, 101, 110, 111,…
Существуют две других системы счисления, которые иногда используются в вычислениях: восьмеричная и шестнадцатеричная.
Восьмеричная система счисления – с основанием 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, а не 12? Потому что числа печатаются в десятичном формате, а 12 в восьмеричном формате = 10 десятичном формате.
Восьмеричная система счисления практически не используется, и мы рекомендуем вам ее избегать.
Шестнадцатеричная система счисления — с основанием 16. В шестнадцатеричной системе мы считаем так: 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, A, B, C, D, E, 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 .
Эта программа печатает:
Поскольку для одной шестнадцатеричной цифры возможны 16 различных значений, мы можем сказать, что одна шестнадцатеричная цифра использует 4 бита. Следовательно, пара шестнадцатеричных цифр может использоваться для точного представления полного байта.
Рассмотрим 32-битное целое число со значением 0011 1010 0111 1111 1001 1000 0010 0110 . Из-за длины и повторяемости цифр его нелегко прочитать. В шестнадцатеричном формате это же значение будет выглядеть так: 3A7F 9826 . Это делает шестнадцатеричные значения полезными как краткий способ представления значения в памяти. По этой причине шестнадцатеричные значения часто используются для представления адресов или необработанных значений в памяти.
До C++14 не было возможности назначить литерал в двоичном формате. Однако шестнадцатеричные пары предоставляют нам для этого полезный обходной путь:
Литералы в двоичном формате и разделители цифр C++14
В C++14 мы можем назначать литералы в двоичном формате с помощью префикса 0b :
Поскольку длинные литералы трудночитаемы, в C++14 также добавлена возможность использования кавычек ( ' ) в качестве разделителя цифр.
Если ваш компилятор несовместим с C++14, он пожалуется, если вы попытаетесь использовать любой из этих приемов.
Печать десятичных, восьмеричных, шестнадцатеричных и двоичных чисел
По умолчанию C++ выводит значения в десятичном формате. Однако вы можете указать ему, что необходимо печатать в других форматах. Печать в десятичном, восьмеричном или шестнадцатеричном формате упрощается благодаря использованию std::dec , std::oct и std::hex :
Эта программа печатает:
Печать в двоичном формате немного сложнее, поскольку std::cout не имеет для этого встроенной возможности. К счастью, стандартная библиотека C++ включает в себя тип std::bitset (в заголовке <bitset> ), который сделает это за нас. Чтобы использовать std::bitset , мы можем определить переменную std::bitset и указать std::bitset , сколько бит мы хотим сохранить. Количество бит должно быть константой времени компиляции. std::bitset может быть инициализирован целочисленным значением без знака (в любом формате, включая десятичный, восьмеричный, шестнадцатеричный или двоичный).
Эта программа напечатает:
Мы также можем создать временный (анонимный) std::bitset для печати одного значения. В приведенном выше коде эта строка:
создает временный объект std::bitset с 4 битами, инициализирует его с помощью литерала 0b1010 , печатает его значение в двоичном формате, а затем отбрасывает временный std::bitset .
Магические числа, и почему это плохо
Рассмотрим следующий фрагмент:
Число, такое как 30 в приведенном выше фрагменте, называется магическим числом. Магическое число – это литерал (обычно число) в середине кода, не имеющий никакого контекста. Что значит 30? Хотя вы, наверное, догадываетесь, что в данном случае это максимальное количество студентов в классе, но это не совсем очевидно. В более сложных программах может быть очень сложно сделать вывод, что представляет собой жестко запрограммированное число, если нет комментария, объясняющего его.
Использование магических чисел обычно считается плохой практикой, потому что, помимо отсутствия контекста, для чего они используются, они создают проблемы, если значение необходимо изменить. Предположим, школа покупает новые парты, позволяющие увеличить количество учеников в классе с 30 до 35, и наша программа должна это отразить. Рассмотрим следующую программу:
Чтобы обновить нашу программу для использования нового размера класса, нам нужно будет обновить константу с 30 до 35. Но как насчет вызова setMax() ? Имеет ли это число 30 то же значение, что и другое число 30? Если да, то его следует обновить. В противном случае его следует оставить в покое, иначе мы можем сломать нашу программу где-нибудь еще. Если вы выполняете глобальный поиск и замену, вы можете случайно обновить аргумент setMax() , хотя он не должен был изменяться. Таким образом, вам нужно просмотреть весь код для каждого экземпляра литерала 30, а затем определить, нужно ли его изменить или нет. Это может занять много времени (и привести к ошибкам).
Хотя мы говорим «магические числа», это относится ко всем видам значений. Рассмотрим следующий пример:
В этом примере только одно число (100), но оно также используется в строках. Если мы решим обновить максимальное количество, скажем, на 200, нам придется обновить три разных случая, где встречается 100.
К счастью, существуют лучшие варианты (символьные константы). Об этом мы поговорим на следующем уроке.
Все о литералах в вопросах разработки

В программировании при составлении программного обеспечения необходимо знать немало особенностей выбранного языка разработки. Во многих из них есть так называемые литералы, значения которых новичкам не всегда понятны.
В данной статье будет рассказано о том, что такое literals, какие у них бывают типы, чем они отличаются друг от друга. В программировании соответствующие ответы значительно упростят процедуру написания контента.
Определение
Литерал в программировании – это безымянная константа. Представляет собой своеобразную запись в имеющемся коде приложения, которая выражена фиксированным значением. Литералами выступают еще и представления значения некоторых типов данных.
Нужно запомнить следующие особенности literal:
- они представлены константами, которые включаются непосредственно в текст имеющегося приложения;
- не могут изменяться по мере обработки программного кода – это одно из их ключевых отличий от переменных;
- изменяются в имеющемся контенте только в режиме редактирования;
- бывают разных типов.
Настоящие именованные константы тоже не подлежат в программировании редактированию во время непосредственного исполнения приложения. В некоторых языках разработки (пример – Delphi) при помощи ключевого слова «const» (без кавычек) иногда обозначаются инициализированные до начала обработки кода статические переменные. Такие компоненты могут редактироваться в процессе работы приложения.
Использовать разнообразные типы литералов не слишком трудно. Но сначала нужно знать, как выглядят соответствующие компоненты. Пример выше поможет лучше разобраться в соответствующем вопросе.
Здесь «1» и «Кот» — это литералы, а string pet и int number – непосредственные переменные.
Разновидности
Почти каждый язык программирования позволяет использовать разнообразные типы literals. В зависимости от «разновидности» будет меняться содержание литерала.
В языках разработки предусматриваются примитивные типы. Они отличаются по синтаксису в ЯП. Далее будут приведены примеры того, в коде выглядят литералы Java и C#. Чаще всего встречаются следующие типы литерала:
- символьный;
- строковый;
- логический;
- пустое значение (null);
- регулярное выражение;
- литералы-функции;
- литералы-объекты.
Далее использование рассматриваемого компонента будет разобрано на примере C# и Java. На второй язык программирования сделан больший упор ввиду его повсеместного и стремительного распространения.
Числа
Первый вариант – это числовые литералы. Они бывают:
- целочисленные;
- с плавающей запятой.
Целочисленный литерал – это почти то же самое, что и целые числа. Соответствующая запись является элементарной. Все числовые компоненты записываются в привычной, «стандартной» форме без указывающих символов и прочих составляющих.
Любое число в Java – это по умолчанию целочисленный literal. Допускается явное задание значения переменной или количества итераций в имеющемся цикле. В Java поддерживаются 4 системы счисления:
- двоичная;
- десятичная;
- шестнадцатеричная;
- восьмеричная.
При рассмотрении числовых литералов в Java нужно запомнить – в JDK 7 появилась возможность записи двоичных значений. Для этого используются префиксы 0b и 0B, а после осуществляется запись с использованием нулей и единиц.
Несмотря на то, что числовые (целые) задаются в разных системах счисления, они будут обрабатываться как десятичные. Это значит, что выход за пределы значений приводят к ошибкам компиляции:
По умолчанию целочисленный literal в Java имеет тип int. Если его «параметр» выйдет за пределы присваиваемой переменной, значит в приложении на этапе компиляции возникнет ошибка. Можно использовать тип long. Для этого в конце строчки необходимо выставить символ «L»:
А вот так выглядит присваивание значения «целому» литералу в C#:
Целочисленные «параметры» могут быть как положительными, так и отрицательными.
С плавающей точкой (вещественные)
Следующий вариант – это дробные числа. Они носят название вещественных или «с плавающей точкой». Означает это то, что литералы могут обозначать не только целые, но и дробные элементы. Особо полезный вариант, если в коде использована функция или иное математическое выражение.
Вещественный тип необходимо можно представить несколькими способами:
- классической десятичной дробью;
- в научном виде (дробь + суффикс в виде e или E и степени 10).
В Java второй вариант сохраняется в переменной и обрабатывается точно так же, как и классическая форма представления.
Числа с плавающей точкой – это значит, что переменная будет иметь тип double по умолчанию. Можно задействовать float. Для этого в конце строки необходимо поставить f или F:
А вот – пример в C#:
Рассматривая типы существующих литералов, нужно запомнить – в Java нельзя создать литерал-объект. К такому элементу имеет отношение только null.
Строковый вариант
Следующий вариант – это строковый literal. По названию становится ясно – он представляет собой какую-то запись. Строковый литерал – это набор символов, заключенных в двойные кавычки в программном коде. Является достаточно распространенным типом. Он применяется на практике так же часто, как и числовой. Строковый literal может включать в себя служебные символы, которые требуется экранировать (escape-последовательности).
Строковый литерал – это самая обычная строка с заданной записью. Не функция и не команда. Служит для того, чтобы использовать в программном коде тот или иной текст:
Если внутри заданной строки нужно отобразить двойную кавычку, ее в C# необходимо предварить обратным слешем. В соответствующем типе поддерживается использование управляющих последовательностей.
Символьные
Символьные литералы в Java представлены кодовыми таблицами Unicode. Каждый символ – это 16-бит. Символьный literal обозначается при помощи одинарных кавычек.
Существуют два вида символьных записей:
- Обычный вариант. Это то, что можно ввести непосредственно с клавиатуры.
- Специальный. Символы, которые не получится напечатать на клавиатуре.
Первый вариант можно указать явно. Если в коде используется служебный символ, нужно экранировать его при помощи обратного слеша. Когда нужно, чтобы в консоли появилась функция (константа), рекомендуется использование строкового типа. Это никакой не магический прием, а информация, о которой должен знать каждый разработчик.
Символы, которые нельзя задать в консоли «по умолчанию», допускается использовать в 16-битовом коде. Для этого он указывается с префиксом \u. В восьмеричном стиле задействован обратный слеш.
В C# среди использующихся типов литералов отдельно выделяют управляющие последовательности. Если компилятор их встречает, то он воспринимает «команду» как существующую, а не как запись «слеш + буква». Шестнадцатеричный код тоже заключается в одинарные кавычки.
Логические
В ЯП существуют различные типы так называемых литералов, составляющие значимую часть кода. Последний распространенный вариант – это логическая разновидность. Принимает всего 2 значения – «истина» и «ложь». Это – «магический» тип, который позволяет работать с переменными вида boolean.
Используется для обозначения констант true и false в приложении:
Использовать соответствующий компонент в блоках с if можно, но такой вариант является моветоном.
Отдельно стоит отметить «магический» тип – null. Это ссылка, которая не указывает ни на один объект. Представлено пустым значением.
Хотите освоить современную IT-специальность? Огромный выбор курсов по востребованным IT-направлениям есть в Otus!
String literal
Каждый s-char (изначально из несырьевых строковых литералов)или r-char (изначально из сырьевых строковых литералов)(с C++11)инициализирует соответствующий элемент(ы)в объекте строкового литерала.s-char или r-char (начиная с C++11)соответствует более чем одному элементу,если и только если он представлен последовательностью из более чем одной кодовой единицы в соответствующей кодировке символов строкового литерала.
Если символ не имеет представления в соответствующей кодировке,
- если строковый литерал является обычным строковым литералом или широким строковым литералом,то он условно поддерживается и кодируется последовательность кодовых единиц,определенная реализацией;
- в противном случае (строковый литерал закодирован в UTF),строковый литерал неверно сформирован.
Каждая числовая управляющая последовательность соответствует одному элементу.Если значение,указанное управляющей последовательностью,вписывается в беззнаковую версию типа элемента,то элемент имеет указанное значение (возможно,после преобразования к типу элемента);в противном случае (указанное значение выходит за пределы диапазона)строковый литерал неправильно сформирован.(начиная с C++23).
Concatenation
Строковые литералы, расположенные рядом, объединяются на этапе перевода 6 (после препроцессора). То есть «Hello,» » world!» дает (единственную) строку «Hello, world!» . Если две строки имеют одинаковый префикс кодировки (или ни один из них не имеет его), результирующая строка будет иметь один и тот же префикс кодировки (или не будет префикса).
Если одна из строк имеет префикс кодировки,а другая нет,то та,которая не имеет префикса кодировки,будет считаться имеющей тот же префикс кодировки,что и другая.
Если рядом находится строковый литерал UTF-8 и широкий строковый литерал,то программа плохо сформирована.
Любая другая комбинация префиксов кодировок может поддерживаться или не поддерживаться реализацией.Результат такого конкатенирования определяется реализацией.
Любая другая комбинация префиксов кодировки является неправильной.
Notes
Нулевой символ ( ‘\0′ , L’\0’ , char16_t() и т. Д.) Всегда добавляется к строковому литералу: таким образом, строковый литерал «Hello» является const char[6] содержащим символы ‘H’ , ‘e’ , ‘l’ , ‘l’ , ‘o’ и ‘\0’ .
Кодирование обычных строковых литералов (1) и расширенных строковых литералов (2) определяется реализацией. Например, gcc выбирает их с помощью параметров командной строки -fexec-charset и -fwide-exec-charset .
Строковые литералы имеют статическую длительность хранения и, таким образом, существуют в памяти на весь срок действия программы.
Строковые литералы могут использоваться для инициализации массивов символов . Если массив инициализируется как char str[] = «foo»; , str будет содержать копию строки «foo» .
Могут ли строковые литералы перекрываться и дают ли последовательные оценки строкового литерала один и тот же объект,не уточняется.Это означает,что одинаковые строковые литералы могут быть равны или не равны при сравнении по указателю.
Попытка изменить строковый литерал приводит к тому,что undefined behavior : они могут храниться в .rodata только для чтения хранилище (например, .rodata ) или объединяться с другими строковыми литералами:
Строковые литералы можно преобразовать и присвоить неконстантным char* или wchar_t* для совместимости с C, где строковые литералы имеют типы char[N] и wchar_t[N] . Такое неявное преобразование устарело.
Строковые литералы нельзя преобразовать или присвоить неконстантному CharT* . Явное приведение (например const_cast ) должно использоваться, если требуется такое преобразование.
Строковый литерал не обязательно является последовательностью символов с нулевым окончанием:если строковый литерал имеет встроенные нулевые символы,он представляет собой массив,содержащий более одной строки.
Если действительная шестнадцатеричная цифра следует за шестнадцатеричным экранированием в строковом литерале,она не будет скомпилирована как некорректная экранирующая последовательность.Конкатенация строк может быть использована в качестве обходного пути:
Хотя конкатенация литералов смешанной ширины строки разрешена в C++11,все известные компиляторы C++отвергают такую конкатенацию,и опыт ее использования неизвестен.В результате,в C++23 разрешение смешанной конкатенации литералов широкой строки удалено.
Example
Defect reports
Следующие отчеты о дефектах,изменяющих поведение,были применены ретроактивно к ранее опубликованным стандартам C++.