Литералы
Литералы - это специальные символы, которые мы можем использовать для более удобной записи кода, или для спецификации типа значения.
Литералы - это не переменные и не ключевые слова, это именно специальные символы.
Очевидное
Когда мы записываем какое-то число в переменную:
int a = 123;
...мы пользуемся целочисленным литералом. В данном примере мы используем целочисленный литерал 123
.
С дробными числами, соответственно, используются литералы с плавающей точкой:
float pi = 3.14
То же самое относится к символам и строкам:
char a = 'A';
std::string b = "ABCDE";
Здесь мы используем строковые и символьные литералы.
Обознечение типа литералов
Логично, что целочисленные, символьные и прочие литералы обозначают значение, которое принадлежит к некому типу данных.
По умолчанию происходит так:
- Целочисленные литералы обозначают тип
int
- Литералы с плавающей точкой обозначают тип
float
- Символьные литералы обозначают тип
char
- Для строковых литералов всё сложнее - они обозначают тип
char[]
, или же массив символов (char
).
Про массивы будем подробнее говорить в следующих уроках.
Но что, если в нашем конкретном случае литерал должен обозначать другой тип? Для этого используются специальные суффиксы.
Думаю, самая критичная ситуация, в которой используются суффиксы - это для строковых и символьных литералов. Если для этих литералов не задать правильный суффикс, данные будут повреждены. Подробнее об этом будет далее.
Целые числа
unsigned int num6{ 1024U }; // U - unsigned int
long num7{ -2048L }; // L - long
unsigned long num8{ 2048UL }; // UL - unsigned long
long long num9{ -4096LL }; // LL - long long
unsigned long long num10{ 4096ULL };// ULL - unsigned long long
Символы и строки (суффиксы те же)
Частично этот синтаксис рассматривался в уроке про типы данных:
wchar_t w_ch = L'Д';
char8_t C1 = u8'a';
char16_t uc2 = u'¢'
char32_t Uc4 = U'🍌'
Почему для символьных и строковых литералов особенно важно указывать эти суффиксы? (далее буду говорить только про символы, чтобы просто не писать много текста - со строками всё то же самое).
Рассмотрим следующий код:
#include <iostream>
int main()
{
wchar_t wide_char = 'Д';
std::wcout << wide_char;
}
Вроде бы, здесь не происходит ничего ужасного. Но что означает запись 'Д'
?
Как мы помним, символьные литералы по умолчанию воспринимаются как тип данных char
. А в этом коде, мы вместо символа из ASCII-таблицы используем Д
.
Когда компилятор будет разбирать этот код, он преобразует символ Д
в какую-то последовательность бит в зависимости от кодировки самого файла с исходным кодом. В файле исходного кода же по сути тоже лежит текст, представленный в определённой кодировке.
И символ Д
в итоге преобразуется в некоторое число бит, которое явно не поместится в один байт. Из-за этого компилятор "обрежет" эти биты и будет воспринимать как char
только первые 8 бит.
Вследствие этого на экран в нашем примере выведется мусорное значение.
На самом деле компилятор по этому поводу даже выведет на экран предупреждение:
warning: multi-character character constant [-Wmultichar]
6 | wchar_t wide_char = 'Д';
Здесь компилятор предупреждает, что мы как будто указали в одинарных скобках больше, чем один символ - это происходит как раз из-за того, что символ Д
занимает в памяти больше 8 бит.
Числа с плавающей точкой
float float_var = 3.14f;
double double_var = 3.14;
long double long_double_var = 3.14l;
Другие формы записи
Те же самые литералы (целочиселнные, строковые, ...) можно записывать в другом формате.
Разделение числа на разряды
При записи целого числа в любом месте между цифрами можно поставить '
.
Так число можно сделать более читаемым:
int large_number = 1000000;
int million = 1'000'000;
То же самое можно использовать и для дробных чисел.
Научная нотация
Дробные числа можно записывать с помощью научной нотации:
double some_value = 4e2;
Запись 4e2
в математическом эквиваленте на самом деле просто обозначает \( 4 \times 10^2 \).
Разные системы счисления
Очень полезной может оказаться также запись числа в разных системах счисления.
Двоичная система счисления:
int binary_number = 0b10010010111;
Шестнадцатиричная система счисления:
int address = 0xFFF87AD;
В такой записи можно использовать те же привычные суффиксы и литералы:
int a = 0b11'01'10;
int b = 0b11001011UU;