Литералы

Литералы - это специальные символы, которые мы можем использовать для более удобной записи кода, или для спецификации типа значения.

Литералы - это не переменные и не ключевые слова, это именно специальные символы.

Очевидное

Когда мы записываем какое-то число в переменную:

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;

Источники